为什么这个无效的子查询不会引发语法错误?

Rav*_* HV 6 sql-server t-sql sql-server-2008-r2

是否有任何解释可以解释为什么 SSMS 没有为以下带有本身无效的子查询的删除查询引发任何编译错误?

以下是重现该行为的步骤序列:

CREATE TABLE [dbo].[delete_test]
(
    [id] [int] IDENTITY(1,1) NOT NULL,
    [name] [nchar](10) NOT NULL
) ON [PRIMARY];
Run Code Online (Sandbox Code Playgroud)

种子数据:

insert dbo.delete_test(name) values(N'a'),(N'b'),(N'c'),(N'd'),(N'e');
Run Code Online (Sandbox Code Playgroud)

创建备份表:

select id, name
  into dbo.delete_test_backup 
  from dbo.delete_test where id > 2;
Run Code Online (Sandbox Code Playgroud)

理想情况下,下面的语句不应执行,即使它执行,也应仅删除id具有已备份值的行:

delete dbo.delete_test where id in (
    select id delete_test_backup 
);
Run Code Online (Sandbox Code Playgroud)

该消息显示删除了 5 行,但我预计只有 3 行被删除:

(5 row(s) affected)
Run Code Online (Sandbox Code Playgroud)

尝试将子查询作为独立执行失败:

select id delete_test_backup ;
Run Code Online (Sandbox Code Playgroud)

无效的列名“id”

下面一个按预期执行:

select id from dbo.delete_test_backup ;
Run Code Online (Sandbox Code Playgroud)

输出 :

id
--
3
4
5
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 9

这与:

(
  SELECT id AS delete_test_backup
)
Run Code Online (Sandbox Code Playgroud)

换句话说,您只是为 分配了一个列别名id,而根本没有对名为 的表的引用delete_test_backup

根据 ANSI 标准,在这种情况下 SQL Server 应该做的事情 - 当它有一个子查询并且id在该范围内没有找到时 - 是遍历外部范围,直到找到一个。如果是,则假定这就是您的意思。

看:

* Microsoft 决定删除所有 Connect 而不是存档内容,并且出于某种原因也删除了知识库文章。

为避免该问题,请始终使用表别名,这使您可以 100% 明确地了解列来自哪个表(不命名每个键列也有id帮助)。当然,您可以意外地忽略这些前缀,就像您忽略了 一样FROM,但是以下语法会如您所料地失败,并且大多数其他遗漏都会给您带来解析错误而不是意外执行:

(
  SELECT x.id FROM delete_test_backup AS x
)
Run Code Online (Sandbox Code Playgroud)