Is there any explanation so as to why SSMS did not raise any compilation error for the below delete query with a subquery that is invalid on its own? Below is the sequence of steps to reproduce the behavior: CREATE TABLE [dbo].[delete_test] ( [id] [int] IDENTITY(1,1) NOT NULL, [name] [nchar](10) NOT NULL ) ON [PRIMARY]; Seed data: insert dbo.delete_test(name) values(N'a'),(N'b'),(N'c'),(N'd'),(N'e'); Create a backup table: select id, name into dbo.delete_test_backup from dbo.delete_test where id > 2; Below statement should ideally not execute and, even if it executes, should only delete rows with `id` values that have been backed up : delete dbo.delete_test where id in ( select id delete_test_backup ); The message shows that 5 rows were deleted, but I expected only 3 rows to be deleted: (5 row(s) affected) Attempt to execute the sub-query as a standalone fails : select id delete_test_backup ; > Invalid column name 'id' Below one executes as expected : select id from dbo.delete_test_backup ; > Output : id -- 3 4 5
This is the same as: ( SELECT id AS delete_test_backup ) In other words, you have merely assigned a column alias to `id`, and there is no reference at all to a table called `delete_test_backup`. According to the ANSI standard, what SQL Server is supposed to do in this case - when it has a subquery and does not find `id` at that scope - is traverse to the outer scope(s) until it finds one. If it does, it assumes that's the one you meant. See: - [Best practices : Properly referencing columns](https://blogs.sentryone.com/aaronbertrand/best-practices-referencing-columns/) - ~~KB #298674~~ - ~~Connect #735178~~ - ~~Connect #624370~~ - ~~Connect #392492~~ - ~~Connect #362016~~ - ~~Connect #265772~~ - ~~Connect #772612~~ > _* Microsoft decided to eradicate all of Connect instead of archiving the content, and also disappeared the knowledge base article for some reason._ To avoid the problem, always use table aliases, which allow you to be 100% explicit about which table a column comes from (not naming every key column `id` helps, too). Of course you can leave these prefixes out accidentally, just like you left out the `FROM`, but the following syntax would have failed as you expect, and most other omissions would have left you with a parsing error rather than accidental execution: ( SELECT x.id FROM delete_test_backup AS x )