COUNT vs SELECT in SQL - sql

What is better approach to check existence of an object in database?
select count(id) as count from my_table where name="searchedName";
OR
select id from my_table where name="searchedName";
And then check if count > 0 or the object is not null (ORM logic)
EDIT:
select id to be valid for Oracle.

The idea should be to that we only need to find one record in order to say that such record exists. This can be done with an EXISTS clause in standard SQL.
select exists (select * from mytable where name = 'searchedName');
returns true if the table contains a record with 'searchedName' and false otherwise.
If you want 0 for false and 1 for true instead (e.g. if the DBMS does not support booleans):
select case when exists (select * from mytable where name = 'searchedName')
then 1 else 0 end as does_exist;
You say you want this for Oracle. In Oracle you can use above query, but you'd have to select from the table dual:
select case when exists (select * from mytable where name = 'searchedName')
then 1 else 0 end as does_exist
from dual;
But for Oracle we'd usually use rownum instead:
select count(*) as does_exist
from mytable
where name = 'searchedName'
and rownum = 1; -- to find one record suffices and we'd stop then
This also returns 1 if the table contains a record with 'searchedName' and 0 otherwise. This is a very typical way in Oracle to limit lookups and the query is very readable (in my opinion).

I'd just call:
select id from my_table where name='searchedName';
Making sure there is an index for the name column.
And then check whether or not the result is empty.

Try with IF EXISTS (
if exists (select 1 from my_table where name = "searchedName")
begin
....
end

Related

SQL AND Clause only if another value exists

I have a basic SQL query where I am selecting data from a core records table. I want to add an AND clause to my statement to filter out the results based on a table variable, only if data actually exists in there.
SELECT
*
FROM
TABLE
WHERE
field = '123'
AND
(gender IN (SELECT gender FROM #genders))
In this case, I am looking for all records where field = 123. My goal here is to say that if #genders contains records, filter by that as well.
However, if #genders is empty and we don't have any data in it, it should include all records.
How can I go about doing this? The temp tables are created based on the user selecting one or more optional pieces of criteria from the UI. If they choose a gender for example, I put their selections into a temp table and then I need to search records that meet that criteria. However, if they don't select a gender, I want to include all records, regardless of what the main record has for the gender field.
SELECT
*
FROM
TABLE
WHERE
field = '123'
AND ((SELECT count(1) FROM #genders) = 0 OR
(gender IN (SELECT gender FROM #genders)))
You can use IF condition:
IF EXISTS(SELECT gender FROM #genders)
BEGIN
SELECT * FROM TABLE
WHERE field = '123'
AND
(gender IN (SELECT gender FROM #genders))
END
ELSE
BEGIN
SELECT * FROM TABLE
END
You are going to think this is odd but it is efficient
SELECT t.*
FROM TABLE t
JOIN GENDERS g
on g.gender = t.gender
and t.field = '123'
union all
SELECT t.*
FROM TABLE t
where not exists (select 1 from genders)
Maybe I'm under-thinking it, but isn't it just this?
SELECT
*
FROM
TABLE AS t
LEFT JOIN
#genders AS g
ON
g.gender = t.gender
WHERE
field = '123'
AND
(g.gender = t.gender OR g.gender IS NULL);
If your query doesn't get too complicated, I'd recommend an if statement. Once you find yourself continually adding if else statement in there, I'd recommend looking into dynamic SQL.
IF EXISTS(SELECT gender FROM #genders)
BEGIN
SELECT * FROM TABLE
WHERE field = '123'
and gender IN (SELECT distinct gender FROM #genders)
END
ELSE
BEGIN
SELECT * FROM TABLE WHERE field = '123'
END

single query that defines 2 tables has same row

query 1
(select count(*) from CALENDAR)
it returns 15
query 2
(select value from PARAMETER where name = 'PLAN_HORIZON')
it returns 15 too only when my programs runs without error. if error occurs,
it returns 10 or other values.
this↓ is wrong sql, but i want a single query which returns True or False.
select if (query1 == query2)
How can I define 2 sql has same result in a query?
The following SQL statement returns 0 or 1. It runs with SQL Server
SELECT CASE WHEN (select count(*) from CALENDAR) = (select value from PARAMETER where name = 'PLAN_HORIZON') THEN 1 ELSE 0 END
Something like this:
select count(*) = 0
from (
select count(*)
from calendar
except
select value
from parameter
where name = 'PLAN_HORIZON'
) t
You didn't specify your DBMS, but the above is standard SQL.
Try this query !
SELECT
CASE
WHEN (select count(*) from CALENDAR) = (select value from PARAMETER
where name = 'PLAN_HORIZON')
THEN true
ELSE false
END ;

Filter if values provided otherwise return everything

Say I have a table t with 2 columns:
a int
b int
I can do a query such as:
select b
from t
where b > a
and a in(1,2,3)
order by b
where 1,2,3 is provided from the outside.
Obviously, the query can return no rows. In that case, I'd like to select everything as if the query did not have the and a in(1,2,3) part. That is, I'd like:
if exists (
select b
from t
where b > a
and a in(1,2,3)
)
select b
from t
where b > a
and a in(1,2,3)
order by b
else
select b
from t
where b > a
order by b
Is there a way to do this:
Without running two queries (one for exists, the other one the actual query)
That is less verbose than repeating queries (real queries are quite long, so DRY and all that stuff)
Using NOT EXISTS with a Sub Query to Determine if condition exists
SELECT b
FROM
t
WHERE
b > a
AND (
NOT EXISTS (SELECT 1 FROM #Table WHERE a IN (1,2,3))
OR a IN (1,2,3)
)
ORDER BY
b
The reason this works is because if the condition exists then the OR statement will include the rows and if the condition does not exist then the NOT EXISTS will include ALL rows.
Or With Common Table Expression and window Function with Conditional Aggregation.
WITH cte AS (
SELECT
b
,CASE WHEN a IN (1,2,3) THEN 1 ELSE 0 END as MeetsCondition
,COUNT(CASE WHEN a IN (1,2,3) THEN a END) OVER () as ConditionCount
FROM
t
)
SELECT
b
FROM
cte
WHERE
(ConditionCount > 0 AND MeetsCondition = 1)
OR (ConditionCount = 0)
ORDER BY
b
I find it a bit "ugly". Maybe it would be better to materialize output from your query within a temp table and then based on count from temp table perform first or second query (this limits accessing the original table from 3 times to 2 and you will be able to add some flag for qualifying rows for your condition not to repeat it). Other than that, read below . . .
Though, bear in mind that EXISTS query should execute pretty fast. It stops whether it finds any row that satisfies the condition.
You could achieve this using UNION ALL to combine resultset from constrained query and full query without constraint on a column and then decide what to show depending on output from first query using CASE statement.
How CASE statement works: when any row from constrained part of your query is found, return resultset from constrainted query else return everything omitting the constraint.
If your database supports using CTE use this solution:
with tmp_data as (
select *
from (
select 'constraint' as type, b
from t
where b > a
and a in (1,2,3) -- here goes your constraint
union all
select 'full query' as type, b
from t
where b > a
) foo
)
SELECT b
FROM tmp_data
WHERE
CASE WHEN (select count(*) from tmp_data where type = 'constraint') > 0
THEN type = 'constraint'
ELSE type = 'full query'
END
;

How to return multiple values using case statement in oracle

I want to return multiple values from a query in oracle. For ex:
select count(*)
from tablename a
where asofdate='10-nov-2009'
and a.FILENAME in (case
when 1 = 1 then (select distinct filename from tablename
where asofdate='10-nov-2009' and isin is null)
else null
end);
I am getting error: ora 01427 single row subquery returns more than one row
Please advice.
Thanks, Deepak
A CASE statement cannot return more than one value, it is a function working on one value.
It is not required for your statement, this statement should work:
select count(*)
from tablename a
where asofdate='10-nov-2009'
and a.FILENAME in (select distinct filename
from tablename
where asofdate='10-nov-2009'
and isin is null);
Maybe you have another usage scenario in mind? Something like this:
Select *
From aTable
Where in CASE
WHEN Then
WHEN Then
ELSE END
Then using CASE may not be the right scenario. Maybe this helps you in the right direction:
Select *
From aTable
Where <Case1> and column1 in <Subselect1>
Or <Case2> and column1 in <Subselect2>
OR Not (<Case1> Or <Case2>) and column1 in <Subselect3>
But this will probably be quite some work for the optimizer ...
The distinct in your Case statement is attempting to return multiple values when only one is allowed, and your SELECT statement will only return one value in one row currently. If you're trying to get the count of each filename, do
SELECT FileName, Count(*)
FROM tablename
WHERE asofdate='10-nov-2009' and isin is null
GROUP BY FileName
Run this query:
select distinct filename from tablename
where asofdate='10-nov-2009' and isin is null
You'll see that it returns more than a single row which causes the ORA-01427.
For all I can tell, you're looking for something like:
select a.filename, count(*)
from tablename a
where a.asofdate = '10-nov-2009'
and exists (
select *
from tablename b
where b.isin is null
and a.asofdate = '10-nov-2009'
and a.filename = b.filename
)
group by a.filename
This would find the count of filenames for a day, for which there exists at least one row where isin is null.
If you edit your question and add an explanation of what you're looking for, you might get better answers.

Referring to results of a sub query in main query

I have a sub query that returns one column, showing as GroupType, I then want to do a CASE function on this result within the main query, however I get an invalid column name when using the CASE statement.
Can i do this in SQL to do I have to refer to it by a different name
SELECT CASE
WHEN
(
SELECT column
FROM othertable
) = 1
THEN '1'
ELSE '2'
END
FROM mytable
To reuse the subquery result:
SELECT subvalue, CASE subvalue WHEN 1 THEN 1 ELSE 2 END
FROM (
SELECT (
SELECT column
FROM othertable
) AS subvalue
FROM mytable
) q