Unexpected results from SELECT FROM WHERE X NOT IN Y - sql

So...
select COUNT(*) cnt from docDocument d
inner join tblAttachment a on d.AttachmentID = a.ID
where
a.ContainerID = 1
Returns 6673
select COUNT(*) from tblAttachment
where
ContainerID = 1
Returns 10372
select COUNT(*) cnt from docDocument d
right join tblAttachment a on d.AttachmentID = a.ID
where
a.ContainerID = 1
AND
d.ID IS NULL
Returns 3699 which makes sense as 10372 - 6673 = 3699
SELECT COUNT(*) FROM
(
select ID from tblAttachment a
where
a.ContainerID = 1
Except
(
SELECT AttachmentId from docDocument
)
) tst
Unsurprisingly returns 3699... However...
select COUNT(*) from tblAttachment a
where
a.ContainerID = 1 AND
a.ID NOT IN
(
SELECT d.AttachmentId from docDocument d
)
I was expecting this to return 3699 but surprisingly it's returning 0.
Can anyone explain these results?

If the subquery returns a null value, the NOT IN is no longer true, and no rows are returned.
Either aviod null values to be returned:
select COUNT(*) from tblAttachment a
where
a.ContainerID = 1 AND
a.ID NOT IN
(
SELECT d.AttachmentId from docDocument d WHERE d.AttachmentId IS NOT NULL
)
Or switch to the "null safe" NOT EXISTS:
select COUNT(*) from tblAttachment a
where
a.ContainerID = 1 AND
NOT EXISTS
(
SELECT * from docDocument d WHERE d.AttachmentId = a.ID
)

Your not in query return nulls value. So its displaying zero records.
This is the below scenario you are getting right now. Let's try to understand that and make the changes.
select *
into #tab1
from (select 'a' Name union all
select 'b'union all
select 'c'union all
select 'd'union all
select 'e') AS A
select *
into #tab2
from (select 'd' Name union all
select 'e' union all
select NULL) AS A
Not Exists
select Name
from #tab1
where not exists (select *
from #tab2
where #tab1.Name = #tab2.Name )
Left Join
select t1.Name
from #tab1 t1
left join #tab2 t2 on t1.Name = t2.Name
where t2.Name is null
Not in
select *
from #tab1
where Name not in (select Name from #tab2)
Note: whenever a Not in query returns NULL, the outer query returns blank data.

You must be having NULL values in docDocument table...That's why you are not getting anything.
Please try like this USE NOT EXISTS
select COUNT(*) from tblAttachment a
where
a.ContainerID = 1 AND
NOT EXISTS
(
SELECT d.AttachmentId from docDocument d
WHERE a.ID = d.ID
)
You can use EXCEPT operator.
select * into #tab1 from (
select 'a' Name union all
select 'b'union all
select 'c'union all
select 'd'union all
select 'e'
)AS A
select * into #tab2 from
(
select 'd' Name union all
select 'e' union all
select NULL
)AS A
SOLUTION
select Name from #tab1
EXCEPT
select * from #tab2
OUTPUT
Name
----
a
b
c
(3 rows affected)

Related

WITH clause in HIVE

In below code temp1 is used 2 times, so hive will be execute the select query in temp1 twice? or just once?
with temp1(
select distinct b as b, f, t1.id as id,
from
table1 t1
join
table2 t2 on (t1.id=t2.id)
),
agg_tbl as
(
select
max(abc) as maxabc,
tbl.t
from(
select
count(*) as cnt, b, f
from
temp1
group by
b, f
) tbl group by tbl.t
),
class_tbl as
(select
case
when bp = 1 then 'abc'
when bp = 2 then 'xyz'
end as class,
bp
from
( select
count(b) as bcount, bp
from
temp1
group by bp
)tbl
)
If that is the case, then using temporary tables will make sense.
Thanks.

compare two tables on SQL server with result to show which column from its associated table

I need to compare two tables on SQL server.
table1
id value
3 5
table2
id value
8 6
SELECT *
FROM
(
SELECT a.id AS a_id, a.value AS a_value
FROM [table1] as a
UNION ALL
SELECT b.id AS b_id, b.value AS b_value
FROM [table2] as b
) tmp
GROUP BY tmp.a_id, tmp.a_value
HAVING COUNT(*) = 1
ORDER BY tmp.a_id
I get result:
a_id a_value
3 5
8 6
I need to know which column is from which table, e.g.
a_id a_value b_id b_value
3 5 8 6
Any help would be appreciated !
Thanks !
What about:
SELECT *
FROM (
SELECT a.id, a.value, 'Table1' AS TableName
FROM [table1] as a
UNION ALL
SELECT b.id, b.value, 'Table2' AS TableName
FROM [table2] as b
) tmp
GROUP BY tmp.id, tmp.value, tmp.TableName
HAVING COUNT(*) = 1
ORDER BY tmp.id
You could add a column for tbl. Something like:
SELECT
m.id
,m.value
INTO #tmp
FROM
(
SELECT a.id AS id, a.value AS value
FROM [table1] as a
UNION ALL
SELECT b.id AS id, b.value AS value
FROM [table2] as b
) m
GROUP BY
m.id
,m.value
HAVING COUNT(*) = 1
CREATE CLUSTERED INDEX ix_tmpidvalue ON #tmp
(
id ASC
,value ASC
)
SELECT *
FROM
(
SELECT a.id AS id, a.value AS value, 'a' tbl
FROM [table1] as a
UNION ALL
SELECT b.id AS id, b.value AS value, 'b' tbl
FROM [table2] as b
) tmp
WHERE EXISTS
(
SELECT 1
FROM #tmp n
WHERE tmp.id = n.id
AND tmp.value = n.value
)
ORDER BY tmp.id

SQL need to return ranges from a column

I have a table that has an integer column named ID with values that may have gaps (e.g. 1,2,3,4,7,8,10,14,15,16,20)
I would like to find a query that would, in the example above, result in this:
1-4
7-8
10
14-16
20
= UPDATE =
Thanks to the code below (which seems to work well in SQL Server), I feel I am very close to getting this to work in MS-Access which is the goal. I'm still getting a syntax error though in my statment which I can't figure out...
SELECT val FROM
(
SELECT islands.PORTID, CSTR(islands.PORTID ) as val
FROM MYTABLE islands
WHERE NOT EXISTS (SELECT * FROM MYTABLE t2 WHERE t2.PORTID = islands.PORTID - 1)
AND NOT EXISTS (SELECT * FROM MYTABLE t2 WHERE t2.PORTID = islands.PORTID + 1)
UNION
SELECT
rngStart.PORTID
,CSTR(rngStart.PORTID ) + '-'
+ CSTR(MIN(rngEnd.PORTID)) as val
FROM MYTABLE rngStart
INNER JOIN MYTABLE checkNext ON checkNext.PORTID = rngStart.PORTID + 1
INNER JOIN
(
SELECT PORTID
FROM MYTABLE tblRangeEnd
WHERE NOT EXISTS (SELECT * FROM MYTABLE t2 WHERE t2.PORTID = tblRangeEnd.PORTID + 1)
) rngEnd on rngEnd.PORTID > rngStart.PORTID
WHERE NOT EXISTS (SELECT * FROM MYTABLE t2 WHERE t2.PORTID = rngStart.PORTID - 1)
GROUP BY rngStart.PORTID
) as tbl
ORDER BY PORTID ASC
SELECT val FROM
(
-- Get the islands
SELECT islands.ID, CAST(islands.ID as varchar(10)) as val
FROM #t1 islands
WHERE NOT EXISTS (SELECT * FROM #t1 t2 WHERE t2.ID = islands.ID - 1)
AND NOT EXISTS (SELECT * FROM #t1 t2 WHERE t2.ID = islands.ID + 1)
UNION
-- Get the ranges
SELECT
rngStart.ID
,CAST(rngStart.ID as varchar(10)) + '-'
+ CAST(MIN(rngEnd.ID) as varchar(10)) as val
FROM #t1 rngStart
INNER JOIN #t1 checkNext ON checkNext.ID = rngStart.ID + 1
INNER JOIN
(
SELECT ID
FROM #t1 tblRangeEnd
WHERE NOT EXISTS (SELECT * FROM #t1 t2 WHERE t2.ID = tblRangeEnd.ID + 1)
) rngEnd on rngEnd.ID > rngStart.ID
WHERE NOT EXISTS (SELECT * FROM #t1 t2 WHERE t2.ID = rngStart.ID - 1)
GROUP BY rngStart.ID
) as tbl
ORDER BY ID ASC
I used a table variable called #t1 but just replace that with your table name.
Here it is in action.
EDIT
To make this work in Access you will have to change the joins a little bit. Try this:
SELECT val FROM
(
SELECT islands.PORTID, CSTR(islands.PORTID) as val
FROM MYTABLE islands
WHERE NOT EXISTS
(SELECT * FROM MYTABLE t2 WHERE t2.PORTID = islands.PORTID - 1)
AND NOT EXISTS
(SELECT * FROM MYTABLE t2 WHERE t2.PORTID = islands.PORTID + 1)
UNION
SELECT
rngStart.PORTID
,CSTR(rngStart.PORTID) + '-' + CSTR(MIN(endPORTID)) as val
FROM MYTABLE rngStart
INNER JOIN
(
SELECT checkNext.PORTID as nextPORTID, rngEnd.PORTID as endPORTID
FROM MYTABLE checkNext
INNER JOIN
(
SELECT rngEnd.PORTID
FROM MYTABLE rngEnd
WHERE NOT EXISTS
(SELECT * FROM MYTABLE t2 WHERE t2.PORTID = rngEnd.PORTID + 1)
) AS rngEnd on rngEnd.PORTID > checkNext.PORTID - 1
) AS checkNext ON checkNext.nextPORTID = rngStart.PORTID + 1
WHERE NOT EXISTS
(SELECT * FROM MYTABLE t2 WHERE t2.PORTID = rngStart.PORTID - 1)
GROUP BY rngStart.PORTID
) as tbl
ORDER BY PORTID ASC
create table #sequence (id int not null primary KEY)
insert into #sequence(id)
select 1
union all select 2
union all select 3
union all select 4
union all select 7
union all select 8
union all select 10
union all select 14
union all select 15
union all select 16
union all select 20
--Find Contig ranges
select l.id as start,
(
select min(a.id) as id
from #sequence as a
left outer join #sequence as b on a.id = b.id - 1
where b.id is null
and a.id >= l.id
) AS fend
from #sequence as l
left outer join #sequence as r on r.id = l.id - 1
where r.id is null;
--Find missing values in sequence
select l.id + 1 as start, min(fr.id) - 1 as stop
from #sequence as l
left outer join #sequence as r on l.id = r.id - 1
left outer join #sequence as fr on l.id < fr.id
where r.id is null and fr.id is not null
group by l.id, r.id;
drop table #sequence
This will give you both the ranges and the gaps between the ranges so you can see what you have or what you need. sample data provided
This will work if you access to function row_number().
with C as
(
select ID,
ID - row_number() over(order by ID) as grp
from YourTable
)
select min(ID) as MinID,
max(ID) as MaxID
from C
group by grp
or with a sub-query instead of a common table expression.
select min(ID) as MinID,
max(ID) as MaxID
from (select ID,
ID - row_number() over(order by ID) as grp
from YourTable) as C
group by grp
Result:
MinID MaxID
----------- -----------
1 4
7 8
10 10
14 16
20 20
Try it on SQL Server https://data.stackexchange.com/stackoverflow/q/119411/
Another try:
SELECT
MIN(i), MAX(i)
FROM (
select
i - (SELECT COUNT(*) FROM tbl t WHERE t.i < tbl.i) g,
i
from tbl
) t
GROUP BY g
It'll be slow for sure, but I don't see other way to number rows in access.

Join Table1 with Table2 using Table1 column values in Table2's conditionals

I have the following select statement...
SELECT ROW_NUMBER() OVER(order by cola) as [id], cola
FROM Table1
That makes up my table of all values I'm wanting to insert as #var, right now it works but I have to specify #var each time...
SELECT #var AS [Cola], (
SELECT COUNT(*)
FROM vwTableA AS Z
WHERE Cola = COALESCE(#var,Cola)
AND NOT EXISTS (
SELECT *
FROM TableB
WHERE Colb = Z.Colb
)
) AS [NewCol1],
(
SELECT COUNT(*)
FROM vwTableB AS Y
INNER JOIN TableC AS C
ON Y.Colc = C.Colc
WHERE Y.Cola = #var
) AS [NewCol2],
(
SELECT COUNT(*)
FROM vwTableC AS X
INNER JOIN TableD AS D
ON X.Colc = D.Colc
WHERE X.Cola = #var
) AS [NewCol3]
So I'm wanting to run this second select through all the values of "cola" from the first Select/Table I showed, instead of having to specify the #var and it only return one row each time. How can I do this?
If you use a Common Table Expression CTE you can use it to join to your other statement
with var as
( SELECT ROW_NUMBER() OVER(order by cola) as [id], cola
FROM Table1)
SELECT var.id AS [Cola], (
SELECT COUNT(*)
FROM vwTableA AS Z
WHERE Cola = COALESCE(var.id,Cola)
AND NOT EXISTS (
SELECT *
FROM TableB
WHERE Colb = Z.Colb
)
) AS [NewCol1],
(
SELECT COUNT(*)
FROM vwTableB AS Y
INNER JOIN TableC AS C
ON Y.Colc = C.Colc
WHERE Y.Cola = var.id
) AS [NewCol2],
(
SELECT COUNT(*)
FROM vwTableC AS X
INNER JOIN TableD AS D
ON X.Colc = D.Colc
WHERE X.Cola = var.id
) AS [NewCol3]
FROM var

query with join of 3 tables

I want a single query to produce the following results..
To result in records that are in table1 and in table2 and were not in table3.
There are more than 10,000 records in each table..so i am looking for an efficient one. In all the table Cono is the primary key..
In detail with tables.
TABLE 1:-
Cono
th-123
th-124
th-125
TABLE 2:-
Cono
th-234
th-245
th-256
TABLE 3:-
Cono
th-124
th-125
th-256
Now i want to have the following records
Result TABLE:-
Cono
th-123
th-234
th-245
Try this
WITH Table1 AS
(
SELECT 'th-123' CONO UNION
SELECT 'th-124' UNION
SELECT 'th-125'
)
,
Table2 AS
(
SELECT 'th-234' CONO UNION
SELECT 'th-245' UNION
SELECT 'th-256'
)
,
Table3 AS
(
SELECT 'th-124' CONO UNION
SELECT 'th-125' UNION
SELECT 'th-256'
)
SELECT CONO
FROM Table1
WHERE NOT EXISTS
(
SELECT 1
FROM Table3
WHERE TABLE1.CONO = TABLE3.CONO
)
UNION ALL
SELECT CONO
FROM Table2
WHERE NOT EXISTS
(
SELECT 1
FROM Table3
WHERE TABLE2.CONO = TABLE3.CONO
)
try this:
select t.cono from Table1 t WHERE NOT EXISTS (SELECT 1
FROM Table3 x WHERE x.cono=t.cono)
UNION
select t.cono from Table2 t WHERE NOT EXISTS (SELECT 1
FROM Table3 x WHERE x.cono=t.cono)
(SELECT t1.Cono FROM table1 t1
LEFT JOIN table3 t3
ON t3.Cono = t1.Cono
WHERE t3.Cono IS NULL)
UNION ALL
(SELECT t2.Cono FROM table2 t2
LEFT JOIN table3 t3
ON t3.Cono = t2.Cono
WHERE t3.Cono IS NULL)
Kind of vague tables and names, but here's what you can do if you REALLY wanna do it in one query:
SELECT Cono
FROM Table3
WHERE NOT EXISTS ( SELECT Cono
FROM TABLE1 as T
WHERE EXISTS ( SELECT *
FROM TABLE2
WHERE T.Cono = TABLE2.Cono));
This should select the values in table 3 that do not exist in the query that was created in parenthesis, which is a table made up of rows that are in tables 1 and 2.
Unfortunately, nesting and efficiency normally don't go hand-in-hand...
this one worked for me... and process fast:
select X.FID, c.id as CID
from
(
select a.id as FID from tbl1 a
union
select b.id as FID from tbl2 b
) as X
left outer join tbl3 c on FID = c.id
where
c.id is null
;
Try this (not tested):
; WITH all_data AS (
SELECT * FROM table1
UNION ALL
SELECT * FROM table2
)
SELECT *
FROM all_data ad
WHERE NOT EXISTS (
SELECT *
FROM table3 t3
WHERE ad.Cono = t3.Cono);