Multiple If Exists with AND and OR - sql

I want to run a set of queries only if a few conditions are true. Please see one example below, I want to combine first 2 conditions and if they are true then enter begin block or else if only 3rd condition is true then enter begin block.
(If Exists(select top 1 * from table1 where [dateInTable]=#date )
and exists (select top 1 * from table2 where [dateInTable]=#date ))
-- Either above 2 are true collectively
OR
-- Or this should be true Individually
(IF exists(select top 1 * from table3 where [dateInTable]=#date))
Begin
-- Logic here
END
if i wrap these in parentheses it won't work and if i remove parentheses it might not consider OR condition as an individual condition and will discard if first 2 conditions are not true. that means 3rd condition will only be evaluated if first 2 are true.

Is this the logic you want?
if ( (exists (select 1 from table1 where [dateInTable] = #date) and
exists (select 1 from table2 where [dateInTable] = #date)
) or
exists(select 1 from table3 where [dateInTable] = #date)
)
begin
-- Logic here
end;
Note that select top 1 * in an exists is just wasted typing. The top does nothing. EXISTS just checks if a row is returned; the contents of the row are irrelevant. So, I just use 1 because it is easy to type.

Related

Update if count is greater than zero otherwise don't do anything

I have two queries, first is a check if value exists in table1, if yes - I'm updating a value in table2, otherwise I return 0 as a count of found values.
It happens really often and I wish I could do that with one query. How would the query look like then?
Maybe you can try something like this. A RETURNING clause will return rows if at least one row was updated in the with clause. It is then verified by an exists check in the select part.
with upd as
(
update table2 t2 set col = 'value4'
where id = ? and exists ( select 1 from table1 t1 where id = ? ) returning *
)
select exists ( select 1 from upd ) :: int as "updated";
This query when run will return 0 ( integer equivalent of boolean false ) when no rows exist and 1 when at least one row was updated.
DEMO
You can join table1 & table2 and then update the value from table2 with table1.

SQL Assign a variable in a SELECT and do a CASE with the variable

Is there any way in doing something like this
declare a variable, assign a value to it in a select statement, then use it in a case ?
Something like this
DECLARE #result BIGINT;
SELECT #result = (SELECT count(_t.Id) FROM T _t WHERE _t.T2Id = _t2.Id GROUP BY _t.T2Id)
CASE WHEN #result IS NULL THEN 0 ELSE #result END AS ColNAme
FROM T2 _t2
The idea is that I would like to avoid doing the select count query twice.
CASE
WHEN (SELECT COUNT(_t.Id) FROM T _t WHERE _t.T2Id = _t2.Id GROUP BY _t.T2Id) IS NULL THEN 0
ELSE (SELECT COUNT(_t.Id) FROM T _t WHERE _t.T2Id = _t2.Id GROUP BY _t.T2Id) END AS ColNAme
I don't want to use functions.
The result set should contain the count of all T items that have a T2 reference by T2 Id
ID | Count
2 | 0
4 | 12
Yes, you can use a variable defined in one select later in the script. But you still use two select queries (note the following doesn't work so read the whole answer):
DECLARE #result BIGINT;
SELECT #result = (SELECT count(_t.Id) FROM T _t WHERE _t.T2Id = _t2.Id GROUP BY _t.T2Id);
SELECT (CASE WHEN #result IS NULL THEN 0 ELSE #result END) AS ColNAme
FROM T2 _t2;
Notes:
The first query will return an error because _t2 is not defined.
The second query should just use COALESCE(#result, 0).
#result will never be NULL, because COUNT() never returns a NULL value. So the second query could really be just select #result.
Returning the same value for every row in T2 is strange. I imagine your actually query is more interesting.
There is no reason to use a variable, unless you need the value later in the script.
So, based on your desired results, I think you simply want a left join and group by:
select t2.id, count(t.id)
from t2 left join
t
on t2.id = t.t2id
group by t2.id;

COUNT vs SELECT in 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

SQL Server IF EXISTS THEN 1 ELSE 2

Using Sql Server 2012. I have a stored procedure and part of it checks if a username is in a table. If it is, return a 1, if not, return a 2. This is my code:
IF EXISTS (SELECT * FROM tblGLUserAccess WHERE GLUserName ='xxxxxxxx') 1 else 2
However, I keep receiving the below error:
Incorrect syntax near '1'.
Is this even possible with an IF EXIST?
Regards,
Michael
If you want to do it this way then this is the syntax you're after;
IF EXISTS (SELECT * FROM tblGLUserAccess WHERE GLUserName ='xxxxxxxx')
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 2
END
You don't strictly need the BEGIN..END statements but it's probably best to get into that habit from the beginning.
How about using IIF?
SELECT IIF (EXISTS (SELECT 1 FROM tblGLUserAccess WHERE GLUserName ='xxxxxxxx'), 1, 2)
Also, if using EXISTS to check the the existence of rows, don't use *, just use 1. I believe it has the least cost.
Its best practice to have TOP 1 1 always.
What if I use SELECT 1 -> If condition matches more than one record then your query will fetch all the columns records and returns 1.
What if I use SELECT TOP 1 1 -> If condition matches more than one record also, it will just fetch the existence of any row (with a self 1-valued column) and returns 1.
IF EXISTS (SELECT TOP 1 1 FROM tblGLUserAccess WHERE GLUserName ='xxxxxxxx')
BEGIN
SELECT 1
END
ELSE
BEGIN
SELECT 2
END
In SQL without SELECT you cannot result anything. Instead of IF-ELSE block I prefer to use CASE statement for this
SELECT CASE
WHEN EXISTS (SELECT 1
FROM tblGLUserAccess
WHERE GLUserName = 'xxxxxxxx') THEN 1
ELSE 2
END
You can define a variable #Result to fill your data in it
DECLARE #Result AS INT
IF EXISTS (SELECT * FROM tblGLUserAccess WHERE GLUserName ='xxxxxxxx')
SET #Result = 1
else
SET #Result = 2
What the output that you need, select or print or .. so on.
so use the following code:
IF EXISTS (SELECT * FROM tblGLUserAccess WHERE GLUserName ='xxxxxxxx') select 1 else select 2

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
;