某天同事回報某資料表的資料被全部刪除了。經過一番追查確定是子查詢的問題。
兩個資料表的架構大致如下
Table A1 Table A2
--------------- ---------------
A1ID A2ID
... A1ID
..... ......
A2資料表為A1資料表的明細資料,彼此之間以A1ID這個欄位關聯。
當A1的資料被刪除時,要連動刪除A2的資料。
很簡單的需求,在A1資料表中加個trigger 一行指令就可以輕鬆搞定
delete A2 form A1ID =(select A1ID from deleted)
本來一直頭好壯壯的運行,直到某天資料庫異動,上面希望統一主Key名稱為ID,於是新的資料架構如下。
Table A1 Table A2
--------------- ---------------
ID ID
... A1ID
..... ......
A2.A1ID對應到A1.ID的欄位
此時照道理原先的trigger應該要失效並處發錯誤才對,因為A1資料表中已經沒有A1ID這個欄位了。
But~~他不但活得好好的還把資料全給刪了,傑克這真是太靠北了。
稍微追查一下原因,主要是因為A2表中有同名的A1ID 當 再子查詢中查無該欄位時,會自動帶入主表的欄位
來看看MSDN怎麼說的(還用重要標起來,看來踩雷的應該不只我一個@@)
重要如果資料行被不存在於由子查詢的 FROM 子句所參考之資料表中的子查詢所參考,但存在於由外部查詢之 FROM 子句所參考的資料表中,則查詢會在沒有錯誤之下執行。 [SQL Server] 會以外部查詢中的資料表名稱,對子查詢中的資料行進行隱含限定。
所以該行trigger 就轉譯成 delete A2 form A1ID =(select A1ID from A2)
然後資料就刪光光了~~~
參考資料:MSDN