【读书笔记】谨防SQL中的两个使用误区:整型相除及in/exists
1. 在SQL Server中整型相除是取整(舍小数),如果要取小数且限制位数,可以用convert(numeric(10,2),a*1.0/b)或是cast(a*1.0/b as numeric(10,2))的方式得到.
2. 对于in/exists(clause)有4点需要注意:
(1) 含义上来说,in/exists都是取的交集,not in/exists都是取的差集.
(2) 语法上来说:
in: where column_name (not) in(clause)
exists: where (not) exists(clause)
(3) 原理上来说:
in: 把外表和内表作hash连接,确定给定的值是否与子查询或列表中的值相匹配. 也就是说,查询clause返回的结果集中是否存在column_name的行(感觉就是数组中是否存在这个值).
exists: 先对where前的主查询进行查询,然后用主查询的结果一个一个的代入exists的查询进行判断,如果为真则输出当前这一条主查询的结果,否则不输出. 也就是说先对外表作loop循环,每次loop循环再对内表进行查询.
(4) 效率上来说:
in/exists: 如果查询的两个表大小相当,那么用in和exists差别不大. 如果一大一小,则子查询表大的用exists,子查询表小的用in. 因为开销应该集中在loop循环中,而不是进出循环---切换至下一行这样的开销.
not in/exists: 无论哪个表大,用not exists都比not in要快. 这是因为前者能用到表上的索引,而后者不能. 最致命的一点在于用not in很可能导致出现致命的Bug,如果子集任一记录为Null值,则用not in的整个查询结果也是空集,而not exists是正确结果集.
summary: 针对整个使用(not) in/exists来说,兼顾效率与正确性,最好使的只有一个,也即开发中使用最为广泛的not exists. 而我们使用(not) in较多的地方只有明确定义clause为一个'数组'(感觉上的数组),即(not) in('a','b','c')
附(not in导致Bug的实例):
create table t1(c1 int,c2 int)create table t2(c1 int,c2 int)goinsert into t1 values(1,2)insert into t1 values(1,3)insert into t2 values(1,2)insert into t2 values(1,null)select * from t1 where c2 not in(select c2 from t2)select * from t1 where not exists(select c2 from t2 where t1.c2=t2.c2)