SQL WHERE Subquery in Field List - sql

I have query like:
SELECT field
FROM table
WHERE
(
SELECT COUNT(*)
FROM table2
WHERE table2.field = table.field
)
!=
(
SELECT COUNT(*)
FROM table3
WHERE table3.field = table.field
)
Now I want to have those WHERE subqueries in my field list like:
SELECT field, count1, count2
FROM table
WHERE
(
SELECT COUNT(*)
FROM table2
WHERE table2.field = table.field
) AS Count1
!=
(
SELECT COUNT(*)
FROM table3
WHERE table3.field = table.field
) AS Count2
Is this possible? Of course I could put those subqueries in the field list, but then I can't compare them.
Any ideas?

You can do this if you use Sql Server:
SELECT field, ca2.c2, ca3.c3
FROM table t
cross apply(SELECT COUNT(*) c2
FROM table2 t2
WHERE t2.field = t.field)ca2
cross apply(SELECT COUNT(*) c3
FROM table3 t3
WHERE t3.field = t.field)ca3
where ca2.c2 <> ca1.c1

Use correlated sub-selects to count. Wrap up in a derived table:
select dt.* from
(
SELECT field,
(SELECT COUNT(*)
FROM table2
WHERE table2.field = table.field) as cnt1,
(SELECT COUNT(*)
FROM table3
WHERE table3.field = table.field) as cnt2
FROM table
) dt
where dt.cnt1 <> dt.cnt2

You just need to use a Derived Table:
select *
from
(
SELECT field,
(
SELECT COUNT(*)
FROM table2
WHERE table2.field = table.field
) AS Count1,
(
SELECT COUNT(*)
FROM table3
WHERE table3.field = table.field
) AS Count2
FROM table
) dt
WHERE Count1 <> Count2

Related

How to retrieve count rows from a table that is filtered using QUALIFY?

To get the number of rows from a table, I can use SELECT COUNT( row-name ) for the joined table.
But this doesn't work if I filter it using QUALIFY ROW_NUMBER() OVER ( PARTITION BY rowx, rowy) = 1
Is there a way to get the total number of rows for a QUALIFY filtered table?
Here is a full example of the query
query = """
SELECT
COUNT(*)
FROM table1
JOIN table2 ON
table1.column1 = table2.column2
JOIN table2 ON
table1.column4 = table3.column5
QUALIFY ROW_NUMBER() OVER
(
PARTITION BY
table3.column6,
table3.column7
) = 1
"""
I also tried
query = """
SELECT
COUNT(*)
FROM (
table1
JOIN table2 ON
table1.column1 = table2.column2
JOIN table2 ON
table1.column4 = table3.column5
QUALIFY ROW_NUMBER() OVER
(
PARTITION BY
table3.column6,
table3.column7
) = 1
)
"""
But it didn't work
Most likely QUALIFY is happening after the COUNT(*) expression is being evaluated. To remedy this, you may take the count of a subquery:
SELECT COUNT(*)
FROM
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY t3.column6, t3.column7) rn
FROM table1 t1
INNER JOIN table2 t2 ON t1.column1 = t2.column2
INNER JOIN table3 t3 ON t1.column4 = t3.column5
) t
WHERE rn = 1;

Count of matching IDs with in C as query

I'm looking to add a column to display a count of all records where the drgpackid matches.
Essentially I want one line in the example provided and a count of how many records have that ID and meet the conditions of the query.
with C as (
select t1.*
from DrgPack t1 join
DrgPack t2
on t1.DrgID = t2.DrgID and t1.CentralMaintFieldMask <> t2.CentralMaintFieldMask
)
select *
from rxworkflowpack
where drgpackid in (select ID from c where CentralMaintFieldMask = 0)
There are a thousand ways to do this, like adding another CTE with the counts and joining to it
with C as (
select t1.*
from DrgPack t1 join
DrgPack t2
on t1.DrgID = t2.DrgID and t1.CentralMaintFieldMask <> t2.CentralMaintFieldMask
),
D as (
select drgpackid, count(*) from rxworkflowpack group by drgpackid)
select *
from rxworkflowpack left join D on rxworkflowpack.drgpackid = d.drgpackid
where drgpackid in (select ID from c where CentralMaintFieldMask = 0)
You can use window function like this:
with C as (
select t1.*
from DrgPack t1 join
DrgPack t2
on t1.DrgID = t2.DrgID and t1.CentralMaintFieldMask <> t2.CentralMaintFieldMask
)
select DISTINCT *, COUNT(*) OVER (PARTITION BY drgpackid) AS CountRecords from rxworkflowpack
where drgpackid in (select ID from c where CentralMaintFieldMask = 0)
You should use < to not double count
select t1.drgpackid, count(*) as cnt
from DrgPack t1
join DrgPack t2
on t1.DrgID = t2.DrgID
and t1.CentralMaintFieldMask < t2.CentralMaintFieldMask
join rxworkflowpack
on rx.ID = t1.drgpackid
and rx.CentralMaintFieldMask = 0
group by t1.drgpackid

How to find difference in rows for two tables in DB2 or SQL Server

In the table1 I have 1421144 rows and table2 has 1421134 rows.
I tried this query, but I don't get any rows returned.
select table1.ID
from table1
where ID not in (select ID from table2)
I have also used this query:
select ID from table1
except
select ID from table2
But I don't get any rows. Please help me, if the table1 has duplicates how can I get those duplicates?
Assuming ids are unique, you can use full outer join in either database:
select coalesce(t1.id, t2.id) as id,
(case when t1.id is null then 'T2 only' else 'T1 only' end)
from t1 full outer join
t2
on t1.id = t2.id
where t1.id is null or t2.id is null;
It is quite possible that the two tables have the same sets of ids, but there are duplicates. Try this:
select t1.id, count(*)
from t1
group by t1.id
having count(*) > 1;
and
select t2.id, count(*)
from t2
group by t2.id
having count(*) > 1;
If you have duplicates, try:
WITH Dups AS(
SELECT ID, COUNT(ID) OVER (PARTITION BY ID) AS DupCount
FROM Table1)
SELECT *
FROM Dups
WHERE DupCount > 1;
If you need to delete the dups, you can use the following syntax:
WITH Dups AS(
SELECT ID, ROW_NUMBER() OVER (PARTITION BY ID ORDER BY ID) AS DupCount
FROM Table1)
DELETE FROM Dups
WHERE DupCount > 1;
Obviously, however, check the data before you run a DELETE statement you got from a random on the internet. ;)
I Guess u have data type mismatch between 2 tables, cast them to integers and try your first query
select table1.ID from table1
where cast(ID as int) not in (select cast(ID as int) from table2)
If you have stored in a different format than int, cast them to varchar and
try with this datatype.
Not in takes longer to execute, use left join instead
select t1id from
(
select t1.id t1Id, t2.Id t2Id from table1 left join table2
on cast(t1.id as int) = cast(t2.id as int)
) x where t2Id is null

How do I count three different distinct values and group on an ID in MS-Access?

So I know MS-Access does not allow SELECT COUNT(DISTINCT....) FROM ..., but I am trying to find a more viable alternative to the usual standard of
SELECT COUNT(*) FROM (SELECT DISTINCT Name FROM table1)
My problem is I am trying to do three separate Count functions and group them on ID. If I use the method above, it is giving me the total unique value count for the whole table instead of the total count for only the value of ID. I tried doing
(SELECT COUNT(*) FROM (SELECT DISTINCT Name FROM table1 as T2
WHERE T2.ColumnA = T1.ColumnA)) As MyVal
FROM table1 as T1
but it tells me I need to specify a value for T1.ColumnA.
The SQL query I am trying to accomplish is this:
SELECT ID
COUNT(DISTINCT ColumnA) as CA,
COUNT(DISTINCT ColumnB) as CB,
COUNT(DISTINCT ColumnC) as CC
FROM table1
GROUP BY ID
Any ideas?
You can use subqueries. Assuming you have a table where each id occurs once:
select (select count(*)
from (select columnA
from table1 t1
where t1.id = t.id
group by columnA
) as a
) as num_a,
(select count(*)
from (select columnB
from table1 t1
where t1.id = t.id
group by columnB
) as b
) as num_b,
(select count(*)
from (select columnC
from table1 t1
where t1.id = t.id
group by columnC
) as c
) as num_c
from <table with ids> as t;
I'm not sure if you'll think this is "viable".
EDIT:
This makes it even more complicated . . . it suggests that MS Access doesn't support correlation clauses more than one level deep (might you consider switching to another database?).
In any case, the brute force way:
select a.id, a.numA, b.numB, c.numC
from ((select id, count(*) as numA
from (select id, columnA
from table1 t1
group by id, columnA
) as a
) as a inner join
(select id, count(*) as numB
from (select id, columnB
from table1 t1
group by id, columnB
) as b
) as b
on a.id = b.id
) inner join
(select id, count(*) as numC
from (select id, columnC
from table1 t1
group by id, columnC
) as c
) c
on c.id = a.id;

Select distinct rows that contain a given set of data

I have a following table:
bid | data
1 | a
1 | b
1 | c
2 | a
3 | c
3 | a
I want to select all bids that contain given set of data.
For example, all bids that 'contains' data "a" and "b" (result should be bid 1), or ones that contain "a" and "c" (1 and 3).
Only solution I could think of is kind of nasty, so I would appreciate some help/suggestions.
My first try:
select bid from my_table as t1 where
exists (select * from my_table t2 where
t2.bid = t1.bid and
t2.data='a'
)
and
exists (select * from my_table t2 where
t2.bid = t1.bid and
t2.data='b'
)
group by bid;
Thanks.
select t1.bid
from table_1 t1
inner join table_1 t2 on t1.bid = t2.bid
where t1.data = 'a' and t2.data = 'c'
By the way:
all bids that 'contains' data "a" and "b" (result should be bid 1)
--> bid 2 also contains data 'a' and 'b'
While I would not recommend this solution for only two variable lookups it's rate of growth for query cost when matching on more variables increases very slowly as opposed to doing an inner join for each match. As a disclaimer I realize that if pipe is a valid field or there are xml encoded charcters that this break.
select e.bid
from myTable e
cross apply ( select '|'+ i.data + '|'
from myTable i
where e.bid = i.bid
for xml path('')) T(v)
where v like '%|A|%' and v like '%|B|%' --and v like '%|C|%'.....
group by e.bid
as a side not about other options your answer could be simplified into
select bid from my_table as t1 where
exists (select * from my_table t2 where
t2.bid = t1.bid and
t2.data='a'
)
and t1.data = 'c'
group by bid;
This is roughly an equivalent of christian's answer. The optimizer will most likely treat these the same.
select distinct t1.bid
from table_1 t1
inner join table_1 t2 on t1.bid = t2.bid
where t1.data = 'a' and t2.data = 'c'
With a subquery, count the number of right occurences you have in your table.
SELECT DISTINCT m.bid
FROM myTable m
WHERE (
SELECT COUNT(1)
FROM myTable m2
WHERE (m2.data = 'a'
OR m2.data = 'b')
AND m.bid = m2.bid
) = 2
Maybe not the best answer but:
select bid from mytable where data = 'a'
intersect
select bid from mytable where data = 'c'
Uses exists:
declare #t table(bid int, data char)
insert #t values(1,'a'),(1,'b'),(1,'c'),(2,'b'),(2,'a'),(3,'c'),(3,'a')
select distinct t1.bid
from #t t1
where exists(
select 1
from #t t2
where t2.bid = t1.bid and t2.data = 'a'
)
and exists(
select 1
from #t t2
where t2.bid = t1.bid and t2.data = 'b'
)
XML PATH and XQuery version:
select distinct t.bid
from
(
select *
, (
select *
from #t t2
where t2.bid = t1.bid
for xml path, root('root'), type
) [x]
from #t t1
) t
where t.x.exist('root[*/data[text() = "a"] and */data[. = "b"]]') = 1