仅当源表中的所有ID都存在于目标表中时,我才想合并2个表. 但不可能在MERGE子句内部引发异常. 我有什么替代 Select 来达到同样的结果?

我试过这个:

MERGE [dbo].[Target] as tgt
USING [dbo].[Source] as src
ON (tgt.ID = src.ID)
WHEN MATCHED THEN
    UPDATE SET tgt.Name = src.Name
WHEN NOT MATCHED THEN 
    THROW 51000, 'error: not all ids match!', 1;

我原以为只有当源表具有目标表中的所有ID时,它才会更新目标表,但是,我得到了一个错误消息:

"抛出"附近的语法不正确.需要DELETE、INSERT或UPDATE.

推荐答案

你不能在MERGETHEN部分使用任意的语句,the syntax对你被允许做的事情有很具体的说明.

如果您想在这样的行上使用THROW,那么只需使用IF EXISTS... WHERE NOT EXISTS即可.然后将MERGE转换为正常连接UPDATE.

因为它现在是两个语句,所以您将需要一个显式的事务和锁定提示.

SET NOCOUNT, XACT_ABORT ON;

BEGIN TRAN;

IF EXISTS (SELECT 1
    FROM dbo.Source as src WITH (SERIALIZABLE)
    WHERE NOT EXISTS (SELECT 1
        FROM dbo.Target as tgt WITH (SERIALIZABLE, UPDLOCK)
        WHERE tgt.ID = src.ID
    )
)
    THROW 50001, N'error: not all ids match!', 1;


UPDATE tgt
SET Name = src.Name
FROM dbo.Target as tgt
JOIN dbo.Source as src ON tgt.ID = src.ID;

COMMIT;

如果您希望错误消息告诉您第一个失败的ID,您可以将其存储在一个变量中,然后判断该变量是否为NULL.

DECLARE @message nvarchar(1000);

SELECT TOP (1)
  @message =  CONCAT(N'error: id ', src.ID, N' is not in target')
FROM dbo.Source as src WITH (SERIALIZABLE)
WHERE NOT EXISTS (SELECT 1
    FROM dbo.Target as tgt WITH (SERIALIZABLE, UPDLOCK)
    WHERE tgt.ID = src.ID
);

IF @message IS NOT NULL
    THROW 50001, @message, 1;

Sql相关问答推荐

提取Snowflake SQL中的嵌套键

当有空单元格时,如何连接列

SQL—如何在搜索的元素之后和之前获取元素?

解析SQL Server中的嵌套JSON

PostgreSQL:使用JSONB中的字段使用jsonb_to_Records()填充记录

将所有XML文件导入到SQL Server中

输出连续出现两次以上的行

如何在android房间中进行多个加入

SQL for Smarties 类型问题:从表中 Select 记录,并对某些值进行分组

在SQL中实现表格数据透视类型报表

按所选的值将记录分组到不同的列中

将有效数字作为 varchar 返回的 SQL 函数

在多个表上递归查找

SQL:如何从时间戳数据生成时间序列并计算不同事件类型的累计总和?

如何防止 SQL 中的负收入值并将其重新分配到接下来的月份?

SQLite 中的过滤运行总和视图

基于源表的 SQL INSERT、UPDATE 和 DELETE

在 Athena / Presto 中提取 JSON 对象以获取动态密钥

如何使用子查询锁定此查询中的选定行?

使用 json_agg 从 SQL 查询获取 [null] 响应