问题所在

我需要查找并删除两个表中所有相同的行,这些表的模式可能经常更改.在本例中,EQUAL表示各行中的所有值彼此相等,例如:

ID Message Date = ID Message Date
1 'Hello' 1/1/1999 == 1 'Hello' 1/1/1999
2 'Hello' 1/1/1999 != 2 'Goodbye' 1/1/1999
3 'Goodbye' null == 3 'Goodbye' null

我希望使用关键字EXCEPT来完成此操作,因为它不需要为每一列指定相等条件,也不需要在查询有非键列名称更改时更新查询.我知道在SELECT中使用通配符是一种糟糕的代码气味,但是这两个表将始终具有相同的非隐藏列,并且以这种方式编写过程将使代码更易于维护.

可能重要的是,表Table1中的一个是时态表,而Table2不是.然而,Table1的历史记录存储在单独的表中,并且查询没有利用SYSTEM_TIME(即,仅查询当前数据).

我try 过的东西

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
)

我一直在try 的是以下内容,我认为应该删除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) 

我不清楚虫子是在什么情况下出现的.

当为DELETE抛出异常时,它处于代数化过程中,调用堆栈如下所示

enter image description here

当执行SELECT ... INTO并将断点放在CRelOp_IntersectExcept::PexprBindSelf上时,调用堆栈如下所示(没有抛出错误).也许CRelOp_SelectQuery::BindTree对这些隐藏列(?!)有一些额外的逻辑.

enter image description here

Sql相关问答推荐

SQL查询视图与连接?

连接三个表的正确方式是什么?在这三个表中,可以显示在一个表上的行将在其他表中显示结果

Oracle中的时间戳

Select 列组(按同一表格中的另一列分组)Laravel 10

将JSON文件导入Postgres 16数据库时出错(22P04上次预期列之后的额外数据)

将两列相加为同一表中的行的查询

SQL数据库规范化与数据插入

需要使用SQLite查询进行一些奇怪的时间转换

SAS proc freq 或 proc sql 获取数据子集和整个数据的频率

将具有嵌套 XML 的列转换为 SQL 中的表格格式?

使用 Oracle SQL Developer 将不同的列值转换为列会导致错误 ORA-01489

如何为 ActiveRecord 联接应用附加条件

如何在 case 语句中使用聚合?

插入行时的行安全策略问题

强制 SQL 始终通过 R 从视图中返回至少一行

使用 regexp_replace 替换所有出现的特殊字符

如何 Select 一列具有最小值而另一列具有给定值的记录?

添加一列并根据其他列值进行填充

过滤具有一对多关系的两个表之间的数据

BigQuery 将一行拆分为多列