想必你们都用过sql中的in语句吧,我这里描述下我遇到的一种in语句问题,并总结一些给你们分享下,不对的地方还但愿大虾指点下。sql
问题描述:IN子查询时,子查询中字段在表中不存在时语句却不报错性能
日常工做中咱们会常常用到in或者not in语句来处理一些问题,好比经过in子查询语句检索符合或者不符合条件的集合结果、批量删除、修改一些符合条件或者不符合条件的集合。但你们是否注意到当子查询中字段名在表中不存在时语句不会报错(会返父查询中全部的结果),若是你们不注意这点,在使用in语句进行批量删除时就可能悲剧了。下面用实例来讲明spa
1 --一个简单的in查询语句 2 select * from tuser where userno in(select userno from filter_barcode)
上面这条语句子查询里,userno 并不存在filter_barcode表中,可是整个语句确能正常执行(执行子查询的话会报字段不存在的提示),并且返回的是tuser表中全部的结果集。若是你们不注意这种状况,一旦不是用来查询,是用来删除的,那整个表数据就被不知不觉给删除了。code
可是当将子查询中userno字段改为一个即再也不tuser也再也不filter_barcode表中的字段,那语句就会报错blog
select * from tuser where userno in(select useno from filter_barcode)索引
Msg 207, Level 16, State 1, Line 1 列名 'useno' 无效。
缘由:原来是在不使用表别名的前提下若是in子查询里字段在内表找不到就会去引用外表的。class
现实状况下子查询引用外层查询的列是正常的,只不过通常不在in子查询中引用外层查询的列。
可是在exists,not exists子查询中用得比较多,select
select a.* from tuser a where exists (select top 1 * from filter_barcode b where a.userno=b.userno) --执行上面这语句就会提示 Msg 207, Level 16, State 1, Line 1 列名 'userno' 无效。
如下四条是我从其余地方看到的,贴出来给你们参考引用
1.子表引用父表列,而本身没有,在子表有数据的状况下,返回全部非空键的父表记录,子表为空,则结果无
2.子表引用父表属性,只有最外层子查询才能引用
3.有前缀标识,按前缀,若是子表父表前缀同样,按4的规则
4.若是无前缀标识惟一性,子查询表也有此字段,那么以局部子查询为准
若是前缀同样,子查询存在此字段,则以子查询表为准,不然以父表的为准方法
总结;为了不这种问题有几个方法供你们参考
一、当须要用到in子查询时,先执行下in里面的子查询语句是否有误,若是误则进行相应修改
二、使用表前缀(别名)才是硬道理,例如
select * from tuser a where a.userno in(select b.userno from filter_barcode b) Msg 207, Level 16, State 1, Line 1 列名 'userno' 无效。 --这样就会进行报错,而不会返回tuser全部的数据
三、使用exists语句来代替in语句
select a.* from tuser a where exists (select top 1 * from filter_barcode b where a.userno=b.userno) Msg 207, Level 16, State 1, Line 2 列名 'userno' 无效。
关于exists和in的区别用法这里就不在讲述,你们能够查询相关资料
对于in 和 exists的区别: 若是子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之若是外层的主查询记录较少,子查询中的表大,又有索引时使用exists。其实咱们区分in和exists主要是形成了驱动顺序的改变(这是性能变化的关键),若是是exists,那么之外层表为驱动表,先被访问,若是是IN,那么先执行子查询,因此咱们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了 ,另外IN是不对NULL进行处理。