28.案例:表间比较IN
我们知道,IN和NOT IN运算符本质上是OR运算,因而必须从OR运算符对于NULL的处理来考虑IN和NOT IN运算符的运算结果。比如下面的SQL语句是等价的:
--从销售单中检索制作过采购单的人 SELECT * FROM T_SaleBill WHERE FBillMakerId IN ( SELECT FBillMakerId FROM T_PurchaseBill )
SELECT * FROM T_SaleBill WHERE FBillMakerId IN ('00006','00004','00001','00002', NULL);
SELECT * FROM T_SaleBill WHERE FBillMakerId='00006' OR FBillMakerId='00004' OR FBillMakerId='00001' OR FBillMakerId='00002' OR FBillMakerId=NULL
而对于NOT IN运算符来说,下面的SQL语句也是等价的:
SELECT * FROM T_SaleBill WHERE FBillMakerId NOT IN ( SELECT FBillMakerId FROM T_PurchaseBill )
SELECT * FROM T_SaleBill WHERE FBillMakerId NOT IN('00006','00004','00001','00002', NULL);
SELECT * FROM T_SaleBill WHERE NOT(FBillMakerId ='00006' OR FBillMakerId ='00004' OR FBillMakerId ='00001' OR FBillMakerId ='00002' OR FBillMakerId =NULL);
在这种情况下,假设当FBillMakerId等于'00005'时,表达式的输出为:
NOT('00005'='00006' OR '00005'='00004' OR '00005'='00001' OR '00005'='00002' OR '00005'=NULL)
我们知道,在SQL中NULL代表“值未知”, “'00005'=NULL”表示判断'00005'是否等于NULL,一个已知的值'00005'是无法确定是否等于一个未知的值的,所以“'00005'=NULL”的返回值也是位置的,所以“'00005'=NULL”的计算结果为NULL。因此上边的条件可以简化为:
NOT(FALSE OR FALSE OR FALSE OR NULL
根据布尔值与NULL的这个运算特性我们得知“FALSE OR FALSE OR FALSE OR NULL”的运算结果为NULL,而一个未知的值做NOT运算,其结果同样是未知的,因此“NOT NULL”的运算结果为NULL,这样“NOT(FALSE OR FALSE OR FALSE OR NULL)”的运算结果为NULL。既然WHERE条件是未知的,那么结果集中的结果是否符合WHERE条件也就是未知的了,因此检索不出任何数据是非常合理的。
既然问题出在空值上面,只要将空值从子查询中过滤掉即可。为子查询中的查询语句增加一个WHERE条件,将所有空值过滤掉。SQL语句如下:
SELECT * FROM T_SaleBill WHERE FBillMakerId NOT IN ( SELECT FBillMakerId FROM T_PurchaseBill WHERE FBillMakerId IS NOT NULL )