为什么 SQL 服务器没有捕捉到这个?子查询中的拼写错误导致意外删除

Why is SQL Server not catching this? Typo in subquery causes accidental delete

我有一个带有子选择的查询,我在其中输入了错误的列(子选择中的 id1)。如果单独执行查询 SQL 服务器会抛出一个错误,这是正确的并且是预期的。但是,如果在以下上下文中作为子查询执行,则不会捕获拼写错误 - 在这种情况下,我的 table 会被清除。这是故意的行为吗?

CREATE TABLE #a1 (id1 INT);
CREATE TABLE #a2 (id2 INT);

INSERT INTO #a1 (id1) VALUES (1), (2), (3);
INSERT INTO #a2 (id2) VALUES (1);

DELETE FROM #a1 WHERE id1 = (SELECT id1 FROM #a2 WHERE id2 = 1);

SELECT * FROM #a1 -- wow, the table is now empty

我预计会抛出错误,但删除查询被解释为

DELETE FROM #a1 WHERE id1 = id1.

是的,这是预期的行为,因为您的查询明确如下所示:

DELETE FROM #a1 WHERE id1=(SELECT #a1.id1 FROM #a2 WHERE #a2.id2=1);

id1 在子查询中是已知的,因为它属于 #a1 并且因为对于每一行你 select 相同的值与你收到的完全相同:

delete from #a1 where id1=id1

但仅用于子查询(即没有删除部分)- id1 未知,因此它按预期显示错误。

在外部查询中声明的 table 中的列在内部查询中可用。这与构建相关子查询时发挥作用的逻辑相同。

所以在这种情况下:

WHERE id1 = (SELECT id1 FROM #a2 WHERE id2=1)

子查询 returns 与 table #a2 中的记录一样多,id1 来自外部查询。只要存在满足条件id2 = 1的唯一记录#a2,这其实就等同于WHERE id1 = id1.

如果您在列名称前加上 table 别名,您会收到错误消息:

DELETE FROM #a1 t1 WHERE t1.id1 = (SELECT t2.id1 FROM #a2 t2 WHERE t2.id2 = 1);

id1 在 table A1.

delete 查询更改为 select,您将会看到。