子查询内的列名拼写错误,但没有“无效的列名”错误

kon*_*ijn -1 sql t-sql sql-server language-lawyer

我有一张桌子,我们称之为A。我想从该表中删除 ID 为 1 和 2 的行。为此,我创建了一个表变量@B,其中包含值 1 和 2,但该列我将命名为PK

现在我这样做:

DELETE FROM A
WHERE ID IN (
    SELECT ID
    FROM @B
)
Run Code Online (Sandbox Code Playgroud)

请注意我的(故意的)编程错误。在子选择中,我使用了错误的列名。意外地,它与表 A 中使用的名称相同。

这应该会导致“无效的列名”错误,对吧?但事实并非如此。它执行。不仅如此,表 A 中的所有数据都被删除。就好像不再有谓词一样。

我创建了一个完整的演示脚本:

-- What happened to my data???

IF OBJECT_ID('tempdb..#JustATable') IS NOT NULL
    DROP TABLE #JustATable

CREATE TABLE #JustATable (
    PK INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
    ID INT NOT NULL,
    NOTE VARCHAR(100) NOT NULL
)

INSERT INTO #JustATable (ID, NOTE)
SELECT database_id, DB_NAME(database_id)
FROM sys.databases;

SELECT NULL [inserted all the rows from sys.databases into the temptable], *
FROM #JustATable;

DECLARE @JustATableVariable TABLE (
    PK INT NOT NULL PRIMARY KEY IDENTITY(1, 1),
    ID_2 INT NOT NULL,
    NOTE VARCHAR(100) NOT NULL
)

INSERT INTO @JustATableVariable (ID_2, NOTE)
SELECT database_id, DB_NAME(database_id)
FROM sys.databases
WHERE database_id = 2;

SELECT NULL [this is my table variable data], *
FROM @JustATableVariable;

DELETE FROM #JustATable
WHERE ID IN (
    SELECT ID_2
    FROM @JustATableVariable
);

SELECT NULL [I have just removed tempdb from the temptable], *
FROM #JustATable;

DELETE FROM #JustATable
WHERE ID IN (
    SELECT ID /* this is the wrong column name but the same name as used in the temptable column */
    FROM @JustATableVariable
);

SELECT NULL [wait...where is my data?], *
FROM #JustATable;
Run Code Online (Sandbox Code Playgroud)

有人可以向我解释一下这是怎么回事吗?以前有人见过这种行为吗?这可能是一个错误吗?

Sal*_*n A 6

在子查询中,... (select id from @b)该列id不是完全限定的。因此根据 SQL 规范,RDBMS 将首先查看表中是否存在 id 列@b。如果没有,它将“向上”搜索,直到在 table 中找到 id 列a。该查询实际上等同于:

delete from a where id in (select a.id from @b)
Run Code Online (Sandbox Code Playgroud)

语法上正确,语义上错误。