Return 1 if number exists in table and 0 otherwise - sql

I want to return 1 if some number already exists in table and 0 otherwise.
I tried something but it doesn't work:
select
case when 100 in (select distinct id from test) then '1'
else '0'
from test
I want something similar to exists function that already exists in PostgreSQL, but instead of true and false I want 1 or 0.

EXISTS yields a boolean result.
The simple way to achieve what you are asking for is to cast the result to integer:
SELECT (EXISTS (SELECT FROM test WHERE id = 100))::int;
TRUE becomes 1.
FALSE becomes 0.
See:
Return a value if no record is found
Or with UNION ALL / LIMIT 1 (probably slightly faster):
SELECT 1 FROM test WHERE id = 100
UNION ALL
SELECT 0
LIMIT 1;
If a row is found, 1 is returned and Postgres stops execution due to LIMIT 1. Else, 0 is returned.
Disclaimer for the UNION ALL solution: this relies on undocumented behavior that Postgres would execute UNION ALL terms in sequence. This used to be the case until Postgres 11, where Parallel Append was added to Postgres. It's actually still the case (currently Postgres 15) for the given example, as retrieving a single row will never trigger a Parallel Append plan. But it remains undocumented behavior, so you might not want to rely on it. See:
Are results from UNION ALL clauses always appended in order?

If the field you are testing is the Primary Key (or some other unique constraint), then you can simply return the count (which will always be 0 or 1):
SELECT count(*) FROM test WHERE id = 100;

it easy and quick:
SELECT ISNULL((SELECT 1 FROM test WHERE id = 100), 0) res

Related

Return a 0 if no rows are found in Microsoft SQL Server

I need your help with this query.
My table CSO_EMP_ORG_DPM_VIE has a column with different keys. Column name is EXT_KEY.
When I receive the same key number in EXT_KEY, I want the SQL code to count the duplicates using this query:
select EXT_KEY
from CSO_EMP_ORG_DPM_VIE
group by EXT_KEY
having count(*) > 1
This is working so far, but when it has no duplicate keys (numbers) in the column, I want it to generate it with 0 zero, and not nothing.
My expected result is; when two keys are the same I want to generate a 1. When no keys are the same, I want to generate an 0. Right now i got no result at all like in the screenshot.
How can I fix this SQL query accordingly?
Thank you in advance.
Use a CASE expression like this:
SELECT EXT_KEY,
CASE WHEN COUNT(*) > 1 THEN 1 ELSE 0 END flag
FROM CSO_EMP_ORG_DPM_VIE
GROUP by EXT_KEY
or if you want 1 result for the table:
SELECT CASE WHEN COUNT(EXT_KEY) > COUNT(DISTINCT EXT_KEY) THEN 1 ELSE 0 END flag
FROM CSO_EMP_ORG_DPM_VIE
It's not blindingly obvious as to what you are asking for. To that end, this query gives a 1/0 result based on having a count greater than 0 for each key...
SELECT
p.EXT_KEY,
EXT_KEY_RESULT = ISNULL((SELECT 1
FROM CSO_EMP_ORG_DPM_VIE c
WHERE c.EXT_KEY = p.EXT_KEY
HAVING COUNT(EXT_KEY) > 0), 0)
FROM
CSO_EMP_ORG_DPM_VIE p
Alternatively, if you are looking to count each of the keys, you could try...
SELECT EXT_KEY, COUNT(EXT_KEY)
FROM CSO_EMP_ORG_DPM_VIE
GROUP BY EXT_KEY
It's always good practice to specify a particular field in the COUNT aggregate, particularly the primary key, as it's faster to reference.
You really need to give us an expected result for your requirements and be very clear about your expectations.
SELECT CASE WHEN COUNT(EXT_KEY) > 0 THEN 1 ELSE 0 AS dupes
FROM CSO_EMP_ORG_DPM_VIE
PLEASE NOTE: Credit here to forpas for providing a smoother answer which I have borrowed.

Specifying a column value in an aggregate function vs using a WHERE clause

I have a database people that looks like this:
I wanted to count the occurrences of state='CA'.
My first attempt was:
SELECT COUNT(state='CA')
FROM people
;
this returned 1 row with a value of 1000. So I thought that there were 1000 people from CA in the database.
This turns out to be incorrect. I know that they are 127, which I can verify with the query
SELECT COUNT(*)
FROM people
WHERE state='CA'
;
which returns 1 row with a value of 127.
I understand how the second query works. However, I do not understand what is wrong with the first one. What is it returning?
If you want to see what's going on, run the query:
select state='CA' from people;
You will see that you will get one result for each row in people, with the value 0 or 1 (or True/False). What you've selected is whether state='CA' for each row, and there will be just as many of those results as there are rows.
You can't constrain a COUNT statement within the statement, you have to do that via the WHERE clause as in your second example.
count is not a sum .. your first query is improper because don't return the number of the rows true .. but the total numbers of not null rows true or false
if you want a filter count you must use a where condition (as your second query) otherwise you must use an if or a a select case inside the sum() function eg:
Select sum(case
when state='CA' then 1 else 0
end) as my_result from People;
or if you want count .. use null and not 0min count
Select count(case
when state='CA' then 1 else null
end) as my_result from People;
Try this-:
Select count(case when state='CA' then 1 else null end) as xyz from People;
1st query will work if you use case when in side count,
like below query will returned count of CA
SELECT sum( case when state='CA' then 1 else 0 end)
FROM people
In first query it is assigning the value 'CA' to the column state for all 1000 rows instead of filtering the values. That is what SELECT does. SELECT does not filter the number of returning rows, it modifies the data.
Whereas in WHERE clause the rows are being filtered first then the SELECT clause runs the COUNT function.
There is a sequence for running the query. It starts from FROM then WHERE, GROUP BY, ORDER BY at the end SELECT will run.
To answer the actual question - why do you get 1000? I'm guessing that there are 1000 rows in your database, or at least 1000 where state is not null. Count will return the number of rows where the thing inside the () is not null and as one of your comments says, the part inside your () will return either true or false, neither of which is null, so will count them all. Your second example is of course the right way to do it.

Is it possible to use the result of a subquery in a case statement of the same outer query?

I am writing a search routine with a ranking algorithm and would like to get this in one pass.
My Ideal query would be something like this....
select *, (select top 1 wordposition
from wordpositions
where recordid=items.pk_itemid and wordid=79588 and nextwordid=64502
) as WordPos,
case when WordPos<11 then 1 else case WordPos<50 then 2 else case WordPos<100 then 3 else 4 end end end end as rank
from items
Is it possible to use WordPos in a case right there? It's generating an error on me , Invalid column name 'WordPos'.
I know I can redo the subquery for each case but I think it would actually re-run the case wouldn't it?
For example:
select *, case when (select top 1 wordposition from wordpositions where recordid=items.pk_itemid and wordid=79588 and nextwordid=64502)<11 then 1 else case (select top 1 wordposition from wordpositions where recordid=items.pk_itemid and wordid=79588 and nextwordid=64502)<50 then 2 else case (select top 1 wordposition from wordpositions where recordid=items.pk_itemid and wordid=79588 and nextwordid=64502)<100 then 3 else 4 end end end end as rank from items
That works....but is it really re-running the identical query each time?
It's hard to tell from the tests as the first time it runs it's slow but subsequent runs are quick....it's caching...so would that mean that the first time it ran it for the first row, the subsequent three times it would get the result from cache?
Just curious what the best way to do this would be...
Thank you!
Ryan
You can do this using a subquery. I will stick with your SQL Server syntax, even though the question is tagged mysql:
select i.*,
(case when WordPos < 11 then 1
when WordPos < 50 then 2
when WordPos < 100 then 3
else 4
end) as rank
from (select i.*,
(select top 1 wpwordposition
from wordpositions wp
where recordid=i.pk_itemid and wordid=79588 and nextwordid=64502
) as WordPos
from items i
) i;
This also simplifies the case statement. You do not need nested case statements to handle multiple conditions, just multiple where clauses.
No. Identifiers introduced in the output clause (the fact that it comes from a sub-query is irrelevant) cannot be used within the same SELECT statement.
Here are some solutions:
Rewrite the query using a JOIN1, This will eliminate the issue entirely and fits well with RA.
Wrap the entire SELECT with the sub-query within another SELECT with the case. The outer select can access identifiers introduced by the inner SELECT's output clause.
Use a CTE (if SQL Server). This is similar to #2 in that it allows an identifier to be introduced.
While "re-writing" the sub-query for each case is very messy it should still result in an equivalent plan - but view the query profile! - as the results of the query are non-volatile. As such the equivalent sub-queries can be safely moved by the query planner which should move the sub-query/sub-queries to a JOIN to avoid any "re-running" in the first place.
1 Here is a conversion to use a JOIN, which is my preferred method. (I find that if a query can't be written in terms of a JOIN "easily" then it might be asking for the wrong thing or otherwise be showing issues with schema design.)
select
wp.wordposition as WordPos,
case wp.wordposition .. as Rank
from items i
left join wordpositions wp
on wp.recordid = i.pk_itemid
where wp.wordid = 79588
and wp.nextwordid = 64502
I've made assumptions about the multiplicity here (i.e. that wordid is unique) which should be verified. If this multiplicity is not valid and not correctable otherwise (and you're indeed using SQL Server), then I'd recommend using ROW_NUMBER() and a CTE.

How can you use COUNT() in a comparison in a SELECT CASE clause in Sql Server?

Let's say you want do something along the following lines:
SELECT CASE
WHEN (SELECT COUNT(id) FROM table WHERE column2 = 4) > 0
THEN 1 ELSE 0 END
Basically just return 1 when there's one or more rows in the table, 0 otherwise. There has to be a grammatically correct way to do this. What might it be? Thanks!
Question: return 1 when there's one or more rows in the table, 0 otherwise:
In this case, there is no need for COUNT. Instead, use EXISTS, which rather than counting all records will return as soon as any is found, which performs much better:
SELECT CASE
WHEN EXISTS (SELECT 1 FROM table WHERE column2 = 4)
THEN 1
ELSE 0
END
Mahmoud Gammal posted an answer with an interesting approach. Unfortunately the answer was deleted due to the fact that it returned the count of records instead of just 1. This can be fixed using the sign function, leading to this more compact solution:
SELECT sign(count(*)) FROM table WHERE column2 = 4
I posted this because I find it an interesting approach. In production I'd usually end up with something close to RedFilter's answer.
You could do this:
SELECT CASE WHEN COUNT(ID) >=1 THEN 1 WHEN COUNT (ID) <1 THEN 0 END FROM table WHERE Column2=4
Reference:
http://msdn.microsoft.com/en-us/library/ms181765.aspx

SQL select statement filtering

Ok, so I'm trying to select an amount of rows from a column that holds the value 3, but only if there are no rows containing 10 or 4, if there are rows containing 10 or 4 I only want to show those.
What would be a good syntax to do that? So far I've been attempting a CASE WHEN statement, but I can't seem to figure it out.
Any help would be greatly appreciated.
(My database is in an MS SQL 2008 server)
Use a union all:
select
// columns
from YourTable
where YourColumn = 3 and not exists (
select 1 from YourTable where YourColumn = 10 or YourColumn = 4)
union all
select
// columns
from YourTable
where YourColumn = 10 or YourColumn = 4
FYI: Orginal question title was "SQL CASE WHEN NULL - question"
CASE WHEN YourColumn IS NULL THEN x ELSE y END
Since there is nothing that compares to NULL and returns true (not even NULL itself), you cant't do
CASE YourColumn WHEN NULL THEN x ELSE y END
only
CASE ISNULL(YourColumn, '') WHEN '' THEN x ELSE y END
but then you lose the ability to differentiate between NULL and the (in this example) empty string.
Depending on the size of your table and its indexes, it may be more efficient to calculate which values you want before the query
declare #UseThree as bit = 1;
if exists (select 1 from testtable where rowval in (10,4))
set #UseThree = 0;
select COUNT(*)
from testtable
where (#UseThree = 1 AND rowval=3)
OR
(#UseThree = 0 AND rowval in (10,4))
The simplest solution would be to do this in two queries:
SELECT ... FROM YourTable WHERE SomeColumn IN (10,4)
If and only if the above query yields no results, then run the second query:
SELECT ... FROM YourTable WHERE SomeColumn = 3
Running two queries may seem "inelegant" but it has advantages:
It's easy to code
It's easy to debug
It often has better performance than a very complex solution
It's easy to understand for a programmer who has to maintain the code after you.
Running two queries may seem like it has extra overhead, but also consider that you won't run the second query every time -- only if the first query has an empty result. If you use an expensive single-query solution, remember that it will incur that expense every time.