问题
我需要从两个表中查找并删除其架构可能经常更改的所有相同行。在这种情况下,相等意味着行中的所有值都彼此相等,例如:
我想利用EXCEPT
来做到这一点关键字,因为它不需要我为每列指定相等条件并在非键列名称更改时更新查询。我知道在选择中使用通配符是一种不好的代码味道,但是这两个表将始终具有相同的非隐藏列,并且以这种方式编写过程将使代码更易于维护。
可能很重要的注释,其中一个表 Table1
是一个时态表,并且 Table2
不是。然而,Table1
的历史记录存储在单独的表中,并且查询未利用SYSTEM_TIME
(即仅查询当前数据)。
我尝试过的
Table1
使用以下脚本创建:
CREATE TABLE Table1 (
ID INT NOT NULL PRIMARY KEY
, ValidFrom DATETIME2 GENERATED ALWAYS AS ROW START HIDDEN NOT NULL
, ValidTo DATETIME2 GENERATED ALWAYS AS ROW END HIDDEN NOT NULL
, PERIOD FOR SYSTEM_TIME (ValidFrom, ValidTo)
)
WITH (SYSTEM_VERSIONING = ON)
Table2
使用以下脚本创建:
CREATE TABLE Table2 (
ID INT NOT NULL PRIMARY KEY
)
我一直在尝试的是以下内容,我认为应该删除 Table1
中的所有条目Table2
中存在所有列的精确匹配:
DELETE FROM [Table1]
WHERE [Table1].[ID] NOT IN (
SELECT ID FROM (
SELECT * FROM [Table1]
EXCEPT
SELECT * FROM [Table2]
) AS INNER_QUERY
)
但是,SQL Server 出现以下意外错误:
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
但是,以下查询可以按预期工作,没有任何问题
SELECT * FROM [Table1]
WHERE [Table1].[ID] NOT IN (
SELECT ID FROM (
SELECT * FROM [Table1]
EXCEPT
SELECT * FROM [Table2]
) AS INNER_QUERY
)
最佳答案
这显然是一个错误。
“隐藏列”抽象有时有点漏洞(other example)。
一种解决方法是将其分为两个步骤
SELECT ID
INTO #Ids
FROM (SELECT *
FROM [Table1]
EXCEPT
SELECT *
FROM [Table2]) AS INNER_QUERY
DELETE FROM [Table1]
WHERE [Table1].[ID] NOT IN (SELECT ID
FROM #Ids)
我不清楚该 Bug 出现的情况。
当DELETE
抛出异常时,它是在代数过程中,调用堆栈如下所示
当执行SELECT ... INTO
并在CRelOp_IntersectExcept::PexprBindSelf
上放置断点时,调用堆栈如下所示(没有抛出错误)。也许 CRelOp_SelectQuery::BindTree 对于这些隐藏列有一些额外的逻辑(?!)。
关于在时态表和非时态表之间使用 EXCEPT 的 SQL 子查询给出表达式数量错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75795040/