Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WHERE IN (SELECT NonExistingColumnName) causes unexpected behaviour

I recently had a situation where I needed to delete some rows from a table and mis-spelt a column name. There was no error thrown and ALL the rows were deleted from the table. Here is a script that reproduces the issue.

There is an Order table with four orders with OrderID. There is a LIST_TO_DELETE table with one ItemID.

I should have used

DELETE TOP(1) FROM #Orders WHERE OrderID IN (SELECT ItemID FROM #LIST_TO_DELETE  )

instead I used

DELETE TOP(1) FROM #Orders WHERE OrderID IN (SELECT OrderID FROM #LIST_TO_DELETE  )

This caused all rows in the #Orders table to be deleted when I only meant to delete one.

CREATE TABLE #Orders (OrderID INT, OrderName VARCHAR(100))
INSERT INTO #Orders(OrderID, OrderName) VALUES (1,'Order One'),(2,'Order Two'),(3,'Order Three'), (4,'Order Four')

CREATE TABLE #LIST_TO_DELETE (ItemID INT);INSERT INTO #LIST_TO_DELETE(ItemID) VALUES (1)

DECLARE @rowcount INT = 1
WHILE @rowcount > 0 
BEGIN
    DELETE TOP(1) FROM #Orders WHERE OrderID IN (SELECT OrderID FROM #LIST_TO_DELETE  )
    SET @rowcount = @@rowcount
END 

SELECT * FROM #Orders

DROP TABLE #Orders
DROP TABLE #LIST_TO_DELETE

In my original code, the Orders table was real and LIST_TO_DELETE was a table variable but it seems to make no difference what table type is used. If I use any column name apart from OrderID or ItemID, I get an error

DELETE TOP(1) FROM #Orders WHERE OrderID IN (SELECT OtherID FROM #LIST_TO_DELETE  )
 Invalid column name 'OtherID'

Why did this code behave this way?

like image 379
Don Avatar asked Sep 07 '17 08:09

Don


2 Answers

This is a known issue.

The following statement will erroneously delete ALL the rows from the users table:

DELETE FROM users WHERE user_id IN (SELECT user_id FROM groups);

even if the groups table does not have a column named user_id.

The following statement will, however, throw an error:

DELETE FROM users WHERE user_id IN (SELECT g.user_id FROM groups g);

Msg 207, Level 16, State 1, Line 1
Invalid column name user_id

EDIT

DELETE TOP(1) FROM #Orders WHERE OrderID IN (SELECT OtherID FROM #LIST_TO_DELETE  )
 Invalid column name 'OtherID'

This throws an error, because OtherID doesn't exist in #Orders

like image 67
Raj Avatar answered Sep 28 '22 21:09

Raj


Read the article to understand what is happening: Qualifying Column Names in Subqueries

The general rule is that column names in a statement are implicitly qualified by the table referenced in the FROM clause at the same level. If a column does not exist in the table referenced in the FROM clause of a subquery, it is implicitly qualified by the table referenced in the FROM clause of the outer query.

like image 28
Denis Rubashkin Avatar answered Sep 28 '22 20:09

Denis Rubashkin