關於sql語句in的使用注意規則

想必你們都用過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進行處理。
相關文章
相關標籤/搜索