SQL where clause with multiple 'not in' checks
This looks like it should be a relatively simple query but can someone please explain why the second query doesn't return rows 2 and 3 but the third one does? Basically, how can I make a query satisfy both 'not in' clauses?
declare @t table (id int identity, code1 char(2), code2 char(2))
insert into @t (code1, code2) values ('AA','BB')
insert into @t (code1, code2) values ('AA','CC')
insert into @t (code1, code2) values ('开发者_JS百科DD','EE')
select * from @t where code1 = 'AA' and code2 = 'BB'
select * from @t where (code1 != 'AA' and code2 != 'BB')
select * from @t t1 left join @t t2 on t2.id = t1.id and t2.code1 = 'AA' and t2.code2 = 'BB' where t2.id is null
* updated *
Thanks for the answers. I was hoping that the "(code1 != 'AA' and code2 != 'BB')" would all need to evaluate, ie the row 1 (AA,BB) would be filtered out but rwo 2 (AA,CC) would be returned.
Is there no simple way to stipulate that two constraints need to be met, that was what I was hoping for by using brackets and the and statement??
For query 2, code1 != 'AA'
is FALSE for your second row.
To make the second query equivalent to the third query you need:
select * from @t where (code1 != 'AA' or code2 != 'BB')
draw a logic table to figure it out:
Row p1 (code1 != 'AA') p2 (code2 != 'BB') p1 AND p2 p1 OR p2
--- ------------------ ------------------ --------- --------
1 false false false false
2 false true false true
3 true true true true
Edit: In response to your update: AND-ing two NOTS together can be counter intuitive (again, draw yourself a logic table if you need to see how it works). A clearer way of using NOT is to move the 'NOT' outside the bracket as Joe suggested:
select * from @t where NOT (code1 = 'AA' or code2 = 'BB')
actually query 2 should only return row 3 because 'DD' != 'AA' AND 'EE' != 'BB'
The second query can not return record 2, because it says "code1 != AA" - this is not true for the second record, so it should just return record 3.
The third query is a left join - and basically no condition for t1 so all the rows for t1 will be returned, even if there is some condition on t2 (rows in t2 will be filtered out by the conditions put, but since it is a left join, it does not affect rows returned by t1)
As a general principle: Fields from a LEFT JOINED table should not show up in the WHERE clause.
SELECT * FROM CUSTOMER
LEFT OUTER JOIN
ORDERS
ON CUSTOMER.CustomerID = ORDERS.CustomerID
WHERE ORDERS.CustomerID <> 1208
The WHERE clause turns this into an INNER JOIN. If you want to exclude 1208, check the ORDERS.CustomerID.
精彩评论