SQL Sybase Query Strange Behaviour - sql

I've got 2 tables with exactly the same structure in the same Sybase database but they're separate tables.
This query works on one of the 2:
select * from table1 where
QUOTA_FIELD >
(SELECT
count(ACCOUNT) FROM
table1 As t1
where SECTOR = t1.SECTOR
AND
STATUS = 'QUOTA'
)
But for the second table I have to change it to this:
select * from table2 as tref where
QUOTA_FIELD >
(SELECT
count(ACCOUNT) FROM
table2 As t2
where tref.SECTOR = t2.SECTOR
AND
STATUS = 'QUOTA'
)
There's a restriction on where this will execute which means it needs to work like in the first query.
Does anyone have any ideas as to why the first might work as expected and the second wouldn't?

Since I am not yet allowed to comment, here as an answer to the question "does anyone...?":
No. I couldn't find anyone :)
This first query cannot work correctly, since it compares a column with itself (as long as the column names are all normal ASCII characters and not some similar looking UNICODE ones). Please give a proof that the result of this query is in every case the same as of query 2.
Also, the second query would normally be done like that: where SECTOR = tref.SECTOR...

You might be looking for something like this in query #1 :
select * from table1 t2 where
QUOTA_FIELD >
(SELECT
count(ACCOUNT) FROM
table1 As t1
where t2.SECTOR = t1.SECTOR
AND
t1.STATUS = 'QUOTA'
)
This explicitly specifies that the table in subquery is joining with the table in outer query ( co-related subquery ).
If this works, use the same idea in query #2

Related

SELECT query to return a row from a table with all values set to Null

I need to make a query but get the value in every field empty. Gordon Linoff give me the clue to this need here:
SQL Empty query results
which is:
select t.*
from (select 1 as val
) v left outer join
table t
on 1 = 0;
This query wors perfectly on PostgreSQL but gets an error when trying to execute it in Microsoft Access, it says that 1 = 0 expression is not admitted. How could it be fixed to work on microsoft access?
Regards,
If the table has a numeric primary key column whose values are non-negative then the following query will work in Access. The primary key field is [ID].
SELECT t2.*
FROM
myTable AS t2
RIGHT JOIN
(
SELECT TOP 1 (ID * -1) AS badID
FROM myTable AS t1
) AS rowStubs
ON t2.ID = rowStubs.badID
This was tested with Access 2010.
I am offering this answer here, even though you didn't think it worked in my edit to your original question. What is the problem?
select t.*
from (select max(col) as maxval from table as t
) as v left join
table as t
on v.val < t.col;
You can use the following query, but it would still need a little "manual coding".
EDITS:
Actually, you do not need the SWITCH function. Modified query below.
Removed the reference to Description column from one line. Still, you would need to use a Text column name (such as Description) in the last line of the query.
For example, the following query would work for the Months table:
select Months.*
from Months
RIGHT OUTER JOIN
(select "" as DummyColumn from Months) Blank_Data
ON Months.Description = Blank_Data.DummyColumn; --hardcoded Description column

Return a rowset and set a variable in an "IN" clause in SQL Server

I want use the SQL Server IN operator and also set a variable to a column value. Is this possible?
My code is like this:
DECLARE #SubkindId as tinyint;
SELECT NAME FROM SampleTable001 WHERE
Id in (SELECT Id, #SubkindId = Subkind FROM SampleTable002)
ORDER BY Name;
My issue is: I want to set the #SubkindId variable in the inner select statement.
Can It Be Done?
In SQL Server you can't SELECT a result set and SET variables in the same statement (though you can in MySQL). Sorry. But there may be another way to get what you want. Unfortunately, what you want is not completely clear.
Assuming you want to do a SELECT and at the same time return another value into a variable, you have to handle the issue that your query can return multiple rows, so in that case, which one would you want to return into #SubkindId?
Now, I may have misunderstood, and instead of trying to pull the column value into the variable, you instead want to pull only the row where the SubkindId matches the value already in the variable (though you didn't show assigning a value to it first, so this seems less likely).
Please confirm which is the case and answer the above questions, and I can help you more.
In the meantime, I'll try to give you answers for both scenarios.
First, let me mention that I recommend against using the IN() syntax with a subquery returning a list of IDs. It is poor practice in my opinion because it usually demonstrates that the person doesn't really know how to JOIN properly, and as soon as the query gets a little complicated, not only that person but even the best professional SQL Server query writer can get lost (... WHERE x IN (SELECT ... WHERE y IN (SELECT ... WHERE z NOT IN (...))) which soon leads to a serious case of what!?!?!?!. Just use JOINs, and if required, semi-joins (introduced with an EXISTS clause).
Query and Return a Value
If what you really wanted was to get access to the values that the SELECT statement found while doing its join, it might look something like this:
DECLARE #KindsAndSubkinds TABLE (
Name varchar(100),
SubkindId tinyint
);
INSERT #KindsAndSubkinds
SELECT
T1.Name,
T2.SubkindId
FROM
dbo.SampleTable001 T1
INNER JOIN dbo.SampleTable002 T2
ON T1.Id = T2.Id
SELECT DISTINCT Name
FROM #KindsAndSubkinds
ORDER BY Name;
-- Now you can something with the `SubkindId`s in the #KindsAndSubkinds table variable.
Just Query
If you really were just trying to query rather than return a value, this is what I would recommend:
DECLARE #SubkindId as tinyint;
SET #SubkindId = 5;
SELECT
T1.Name
FROM
dbo.SampleTable001 T1
INNER JOIN dbo.SampleTable002 T2
ON T1.Id = T2.Id
WHERE
T2.Subkind = #SubkindId
ORDER BY
T1.Name;
If there are multiple rows in SampleTable002 but you don't want them in the result set, then:
SELECT
T1.Name
FROM
dbo.SampleTable001 T1
WHERE
EXISTS (
-- This semi-join requires at least one row to exist
-- but doesn't increase the row count
SELECT *
FROM dbo.SampleTable002 T2
WHERE
T1.Id = T2.Id
AND T2.Subkind = #SubkindId
)
ORDER BY
T1.Name;
I hope this helps.
Do it like this:
DECLARE #SubkindId as tinyint
SELECT [NAME]
FROM SampleTable001
WHERE Id in (SELECT Id
from SampleTable002
WHERE Subkind=#SubkindId)
order by [Name]
or by using JOIN
DECLARE #SubkindId as tinyint
SELECT [NAME]
FROM SampleTable001 a
INNER JOIN SampleTable002 b
ON a.id = b.id
WHERE b.Subkind=#SubkindId
order by [Name]

SQLite: detect if a rowid exists

What's the best/right/fastest/most appropriate way to detect if a row with a given rowid exists?
Or by extension, hwo to detect if at least one row matching a given condition exists?
I'm firing quite some of these requests. I am currently using
SELECT 1 FROM table WHERE condition LIMIT 1
looks a bit weird to me, but looks to me like "the least work" for the db, however, my SQL knowledge is spotty.
I would probably do it something like this:
SELECT
CASE
WHEN EXISTS(SELECT NULL FROM table1 WHERE ID=someid)
THEN 1
ELSE 0
END
To Count the rows is not that effective.
To check if something exists is in most cases more effective
Since it's sqlite, you need to use the column name "rowid" to access that id column. Using Craig Ringer's sql, the sqlite version would look like this:
SELECT EXISTS(SELECT 1 FROM table WHERE rowid = insert_number)
Use EXISTS, it sounds perfect for what you are after. e.g.
SELECT *
FROM T1
WHERE EXISTS (SELECT 1 FROM T2 WHERE T2.X = T1.X AND T2.Y = 1)
It is effectly the same as LIMIT 1 but is generally optimised better.
One could test
select true from table where id = id1
You can for example use
SELECT COUNT(*) FROM table WHERE ID = whatever

SQL: Get a random entry iff condition is false

Using Firebird:
I want to select a random entry in the table if the first SQL query returns 0 rows. Is there anyway to combine these two queries?
SELECT * FROM table WHERE cond=1;
SELECT FIRST 1 * FROM table ORDER BY rand();
Im using ExecuteNativeQuery on the java-side which takes basic SQL statements. Sadly, If-Else statements don't work. And if i could make a single query to the database instead of two, that would make my code appear faster.
try this: Not sure but think it will work...
Select FIRST 1 t1.*
FROM table t1
left Join Table t2
On t2.pk = t1.pk
And t2.cond=1
ORDER BY Case When t2.Cond = 1
Then 0 Else rand() End
if(exists(select 1 from table where cond=1))
SELECT * FROM table WHERE cond=1;
else
SELECT FIRST 1 * FROM table ORDER BY rand();
something like this, though I forgot whether the then keyword is needed in if statements in FirebirdSQL databases.

Use of CASE statement values in THEN expression

I am attempting to use a case statement but keep getting errors. Here's the statement:
select TABLE1.acct,
CASE
WHEN TABLE1.acct_id in (select acct_id
from TABLE2
group by acct_id
having count(*) = 1 ) THEN
(select name
from TABLE3
where TABLE1.acct_id = TABLE3.acct_id)
ELSE 'All Others'
END as Name
from TABLE1
When I replace the TABLE1.acct_id in the THEN expression with a literal value, the query works. When I try to use TABLE1.acct_id from the WHEN part of the query, I get a error saying the result is more than one row. It seems like the THEN expression is ignoring the single value that the WHEN statement was using. No idea, maybe this isn't even a valid use of the CASE statement.
I am trying to see names for accounts that have one entry in TABLE2.
Any ideas would be appreciated, I'm kind of new at SQL.
First, you are missing a comma after TABLE1.acct. Second, you have aliased TABLE1 as acct, so you should use that.
Select acct.acct
, Case
When acct.acct_id in ( Select acct_id
From TABLE2
Group By acct_id
Having Count(*) = 1 )
Then ( Select name
From TABLE3
Where acct.acct_id = TABLE3.acct_id
Fetch First 1 Rows Only)
Else 'All Others'
End as Name
From TABLE1 As acct
As others have said, you should adjust your THEN clause to ensure that only one value is returned. You can do that by add Fetch First 1 Rows Only to your subquery.
Then ( Select name
From TABLE3
Where acct.acct_id = TABLE3.acct_id
Fetch First 1 Rows Only)
Fetch is not accepting in CASE statement - "Keyword FETCH not expected. Valid tokens: ) UNION EXCEPT. "
select name from TABLE3 where TABLE1.acct_id = TABLE3.acct_id
will give you all the names in Table3, which have a accompanying row in Table 1. The row selected from Table2 in the previous line doesn't enter into it.
Must be getting more than one value.
You can replace the body with...
(select count(name) from TABLE3 where TABLE1.acct_id = TABLE3.acct_id)
... to narrow down which rows are returning multiples.
It may be the case that you just need a DISTINCT or a TOP 1 to reduce your result set.
Good luck!
I think that what is happening here is that your case must return a single value because it will be the value for the "name" column. The subquery (select acct_id from TABLE2 group by acct_id having count(*) = 1 ) is OK because it will only ever return one value. (select name from TABLE3 where TABLE1.acct_id= TABLE3.acct_id) could return multiple values depending on your data. The problem is you trying to shove multiple values into a single field for a single row.
The next thing to do would be to find out what data causes multiple rows to be returned by (select name from TABLE3 where TABLE1.acct_id= TABLE3.acct_id), and see if you can further limit this query to only return one row. If need be, you could even try something like ...AND ROWNUM = 1 (for Oracle - other DBs have similar ways of limiting rows returned).