Reputation: 4807
I have table 1 as:
Name Name2 Number
asd voe 1.00
rt casg 4.00
qdef fr 62.00
erfr cre 25.00
fgf sewq 55.50
ytyt dsvf 68.50
ujer wqw 81.50
uyjum vtr 94.50
I want to select all columns from table 1 which do not match:
Name2 Number
cre 25.00
sewq 55.50
casg 4.00
i.e. my final output should be:
Name Name2 Number
asd voe 1.00
qdef fr 62.00
ytyt dsvf 68.50
ujer wqw 81.50
uyjum vtr 94.50
Right now I am doing it in two stages where I use Except
statement and temp tables.
Is there a smarter way to do this?
Upvotes: 1
Views: 118
Reputation: 37313
If the data is in another table, You can use NOT EXISTS
(recommended)
SELECT * FROM TABLE1
WHERE
NOT EXISTS (SELECT 1 FROM TABLE2 AS T2 WHERE T2.NAME2 = NAME2 AND T2.NUMBER = NUMBER)
Or a LEFT JOIN
SELECT T1.*
FROM TABLE1 T1 LEFT JOIN TABLE2 T2
ON T1.NAME2 = T2.NAME2 AND T1.NUMBER = T2.NUMBER
WHERE T2.NAME2 IS NULL
For more info, read this article it contains useful information on not in vs not exists vs left join
Upvotes: 2
Reputation: 7918
What you are doing are trying to accomplish is described as an left anti semi join in relational algebra. If you look at the actual execution plan for each of Gordon's solutions SQL server uses the Nested Loops Anti Semi Join algorithm to filter the rows. In SQL Server you can perform an anti semi join using NOT IN and NOT EXISTS logical operators as Gordon demonstrated. If you did not need to return the Name column from table1 you could also perform an anti semi join using EXCEPT which is a set operator. The solution using EXCEPT would look like this:
SELECT name2, number FROM table1
EXCEPT
SELECT name2, number FROM table2;
The advantage of EXCEPT over NOT EXISTS and NOT IN is cleaner code. A key disadvantage is how set operators (EXCEPT, INTERSECT and UNION [|ALL]) requires you to have an equal number of columns in each referenced table/set.
Upvotes: 2
Reputation: 1269443
The canonical way would be not exists
:
select t1.*
from table1 t1
where not exists (select 1
from table2 t2
where t2.name2 = t1.name2 and t2.number = t1.number
);
As Hadi shows you can also write this as a left join
.
Contrary to the comment, you can do this using not in
, with a correlated subquery:
select t1.*
from table1 t1
where t1.number not in (select t2.number
from table2 t2
where t2.name2 = t1.name2
);
(Other databases do support not in
on tuples; SQL Server is not one of them.)
I strongly advocate using not exists
or left join
, because the above has unexpected behavior when there are NULL
values in table2
.
Also, this is not safe if number
is stored as a floating point number. This should be fine if number
is a decimal
/numeric
type.
Upvotes: 2