SELECT query for two variables in the same table - sql

I am asking you how can I mimic this logic in SQL:
SELECT var1, var2 FROM table1,WHERE var1 = COUNT(table1.status == 1) AND var2 = COUNT(table2.status == 2)
I want to store in var1 the number of entries that have status = 1 and in var2 the number of entries which have status = 2 in a single SELECT.

You can use COUNT combined with CASE:
SELECT
COUNT(CASE WHEN t1.Status = 1 THEN 1 END) AS var1,
COUNT(CASE WHEN t1.Status = 2 THEN 1 END) AS var2
FROM table1 t1;
Alternatively you can use SUM:
SELECT
SUM(t1.status = 1) AS var1,
SUM(t1.status = 2) AS var2
FROM table1 t1;

If your table is large and has an index on the status column, you need to be able to use an index to get fast exection (two index lookups are faster than one table scan), and that requires to filter the rows with WHERE.
If you can handle the result as two rows, use a compound query:
SELECT count(*) FROM Table1 WHERE status = 1
UNION ALL
SELECT count(*) FROM Table1 WHERE status = 2;
If you need the results in two columns, you can use subqueries:
SELECT (SELECT count(*) FROM Table1 WHERE status = 1) AS var1,
(SELECT count(*) FROM Table1 WHERE status = 2) AS var2;

If you want set two result difference in two variables in a one row this is the option.
SELECT
#var1 = t1.column,
#var2 = t2.column
FROM table1 t1 INNER JOIN table1 t2 ON
a.column = 'value' AND
b.column = 'value2';

Use subquery,Fetch count using count() method of sql
So,
SELECT var1, var2 FROM table1 WHERE var1 = (SELECT count(*) from table 1 where table1.status == 1) AND var2 = (SELECT count(*) from table 1 where table1.status == 2)

Related

Multiple columns return in CASE Statement SQL

I have two tables and based on the sum of a field in TABLE1 I have to return different datasets from TABLE2:
I am trying to achieve this through a Case statement but getting an error saying subselect must have only one field.
Is there a better way to do this? simply when the sum of a column in table1 is 0 do not select anything from table2
TABLE1:
TABLE2:
MY SQL:
SELECT
CASE
WHEN SUM(transaction_unit_failed) > 0
THEN (
SELECT sale_event_nr, business_unit, transaction_nr, transaction_unit_failed_number
FROM TABLE2
)
WHEN SUM(transaction_unit_failed) = 0
THEN (
SELECT sale_event_nr, business_unit, transaction_nr, transaction_unit_failed_number
FROM TABLE2
WHERE 1 = 2
)
FROM TABLE1
select * from table2
where exists (
select 1
from table1
having sum(transaction_unit_failed) > 0
);
Similarly:
select * from table2
where (
select sum(transaction_unit_failed)
from table1
) > 0;
https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=3f68d250bc9a3235767b86626092799e
You could certainly write it as a join if there were a compelling reason. It would eliminate the convenience of nicely using * to return only the columns from the one table.
select *
from table2 inner join (
select sum(transaction_unit_failed) as stuf
from table1
) on stuf > 0;
SELECT sale_event_nr, business_unit, transaction_nr, transaction_unit_failed_number
FROM TABLE2
WHERE (SELECT SUM(transaction_unit_failed) > 0
FROM TABLE1)

SQL AND to see if two flags are set in two different tables?

SELECT 1 FROM
(SELECT 1 FROM mytable1 WHERE parentid = 'ID1' AND flag = 'Y') as X,
(SELECT 1 FROM mytable2 WHERE id = 'ID2' AND flag = 'Y') as Y
I'm making a query to see if two flags are set in two tables, where 'parentid' and 'id' are both primary keys. The query should return a row only if both flags are set to 'Y', or return nothing otherwise, then I do stuff with that result in my backend code.
I've tested this and it works but I feel like it looks wonky and could be optimized. Any ideas?
To get what You want:
SELECT 1
FROM mytable1 AS a, mytable2 AS b
WHERE a.parentid = 'ID1' AND a.flag = 'Y'
AND b.id = 'ID2' AND b.flag = 'Y'
But in fact, I would prefer a query with LEFT JOIN, which always gives one row, like this:
SELECT CASE WHEN a.flag = 'Y' AND b.flag = 'Y' THEN 1 ELSE 0 END AS result
FROM TABLE ( VALUES 1 ) AS always(present)
LEFT JOIN mytable1 AS a ON a.parentid = 'ID1'
LEFT JOIN mytable2 AS b ON b.id = 'ID2'
Your query is fine (although I would use CROSS JOIN. However, I would prefer a row with a specific value. I would phrase that as:
SELECT (CASE WHEN EXISTS (SELECT 1 FROM mytable1 WHERE parentid = 'ID1' AND flag = 'Y') AND
EXISTS (SELECT 1 FROM mytable2 WHERE id = 'ID2' AND flag = 'Y')
THEN 1 ELSE 0
END) as flag
You may need from dual, depending on your database.
It better to use JOIN instead of doing subqueries
SELECT mytable1.parentid, mytable2.id
FROM mytable1
JOIN mytable2 ON mytable2.flag = "Y" AND mytable1.flag = "Y"

Select query 0=0 Vs not exists

I have a table contains 100 million rows and I found the below query (A), which is taking time. I am thinking to change it to (B), is it the same?
Is this query (A) :
SELECT *
FROM tab1
WHERE code = 1
AND TYPE = 'A'
AND 0 = (SELECT Count(1)
FROM tab1
WHERE code = 1
AND tr_type = 'APPROVE'
AND security = 'Y')
Similar to this (B) ?
SELECT *
FROM tab1
WHERE code = 1
AND TYPE = 'A'
AND NOT EXISTS (SELECT 1
FROM tab1
WHERE code = 1
AND tr_type = 'APPROVE'
AND security = 'Y'
AND ROWNUM = 1)
I would recommend writing the query as:
SELECT t1.*
FROM tab1 t1
WHERE t1.code = 1 AND
t1.TYPE = 'A' AND
NOT EXISTS (SELECT 1
FROM tab1 tt1
WHERE tt1.code = t1.code AND
tt1.tr_type = 'APPROVE'
tt1.security = 'Y'
);
The changes are:
Table aliases are introduced.
All columns are qualified.
The rownum = 1 condition is removed.
The latter is between redundant and dangerous. EXISTS/NOT EXISTS is already looking for any row that matches. Including rownum could affect the optimizer.
Your first version has to find all matches in order to calculate the count. That can be much more expensive that determining that there are no matches or finding the first one.
For performance, you want indexes on tab1(code, tr_type, security) and tab1(code, type).
Yes same query.
SELECT *
FROM tab1
WHERE code = 1
AND type = 'A'
AND 0 = (SELECT Count(1)
FROM tab1
WHERE code = 1
AND tr_type = 'APPROVE'
AND security = 'Y')
If we will take output of inner query in the above query
SELECT Count(1)
FROM tab1
WHERE code = 1
AND tr_type = 'APPROVE'
AND security = 'Y'
I am assuming , Record with code = 1 , TR_TYPE = 'APPROVE' and security = 'Y' is present. So output will be 1. (Assumption is only one matching record is present).
SELECT *
FROM tab1
WHERE code =1
AND type='A'
AND 0=1 (replacing the result)
So this will not return any data as 0 is never equal to 1.
SELECT *
FROM tab1
WHERE code = 1
AND type = 'A'
AND NOT EXISTS (SELECT 1
FROM tab1
WHERE code = 1
AND tr_type = 'APPROVE'
AND security = 'Y'
AND rownum = 1)
Now checking the above query, inner query return 1 as the data with the where clause is present so result will be
SELECT *
FROM tab1
WHERE code =1
AND type='A'
AND NOT EXISTS (1)
Exists(If any record found) = true and in our case Exists(1) = true so
Not Exist (1) = false. Which denotes to false as it has 1 record , so it will also not return the data.
So if you are asking that both query will return same output. So It will return same output.
Yes the output will be same because its just the interchangeable way to use it however in terms of time complexity the second one is optimised.
Yes they are the same, however i would explicitly put an alias on the table being used in the non exists and alias the columns being compared to.Eg:
SELECT *
FROM tab1
WHERE code = 1
AND type = 'A'
AND NOT EXISTS (SELECT 1
FROM tab1 b
WHERE b.code = 1
AND b.tr_type = 'APPROVE'
AND b.security = 'Y'
AND rownum = 1)

Checking whether two tables have identical content

How can I check and store in variable whether two tables have identical content?
I have table variable with data like
declare #table1 table (id int)
insert into #table1 (id) values (1), (2), (3)
and as the second table I have query
select T.id from SomeTable T
inner join #table1 T1 on T.id = T1.id
the query returns data:
id
-----
1
2
In this case I need write false(0) into declare #HasAccess BIT variable.
When the query returns data:
id
-----
1
2
3
then I need write true(1) into #HasAccess
Hmmm. There are various ways.
Given that you have one column, you can do:
select (case when count(*) = 0 then 1 else 0 end)
from t1 full join
t2
on t1.id = t2.id
where t1.id is null or t2.id is null;
This checks if an id doesn't match in either table.
Another way uses union all:
select (case when count(*) = 0 then 1 else 0 end)
from (select id, sum(in_t1) as num_t1, sum(in_t2) as num_t2)
from ((select id, 1 as in_t1, 0 as in_t2 from table1) union all
(select id, 0, 1 from table2)
) tt
group by id
) tt
where num_t1 <> 1 or num_t2 <> 1;
Another option (just for fun). This will compare the entire table fields and values.
I suspect not the best option for LARGE tables
Example
Select IsIdentical = case when (Select * from Table1 Order by id For XML Raw)
= (Select * from Table2 Order by id For XML Raw)
then 1 else 0 end
EDIT - Option with Inner Join
Select IsIdentical = case when (Select * from #Table1 Order by id For XML Raw)
= (Select A.*
From SomeTable A
Join #Table1 B on A.ID=B.ID
Order By id For XML Raw)
then 1 else 0 end
Using EXCEPT:
SET #HasAccess = ISNULL(
( SELECT 0
WHERE EXISTS(
SELECT ID /* add more columns here if needed */
FROM #table1
EXCEPT
SELECT ID /* add more columns here if needed */
FROM SomeTable )), 1 )
Explanation:
Return all IDs from #table1, except those found in SomeTable
Return 0 (false) if any records have been returned by [1].
If no records returned by [1] the main query will return NULL, hence the ISNULL
Advanatages
Can easily be extended to comparisons on more than one column.

Select on records based on two column criterias

I would like to do an SQL query to select from the following table:
id type num
1 a 3
1 b 4
2 a 5
2 c 6
In the case where they have the same 'id' and be type 'a or b', so the result would look something like this:
id type num
1 a 3
1 b 4
Any one has any idea how that can be accomplished?
SELECT table1.*
FROM table1,
(
SELECT COUNT(*) as cnt, id
FROM (
SELECT *
FROM table1
WHERE type = 'a' OR type = 'b'
) sub1
GROUP BY id
HAVING cnt > 1
)sub2
WHERE table1.id = sub2.id
Tested here: http://sqlfiddle.com/#!2/4a031/1 seems to work fine.
Method 1:
select a.*
from some_table t
join some_table a on a.id = t.id and a.type = 'a'
join some_table b on b.id = t.id and b.type = 'b'
Method 2:
select *
from some_table t
where exists ( select *
from some_table x
where x.id = t.id
and x.type = 'a'
)
and exists ( select *
from some_table x
where x.id = t.id
and x.type = 'b'
)
The first technique offers the possibilities of duplicate rows in the results set, depending on the cardinality of id and type. The latter is guaranteed to provide a proper subset of the table.
Either query, assuming you have reasonable indices defined on the table should provide pretty equivalent performance.