当前位置: 首页 > 面试题库 >

为什么在MERGE语句的“ UPDATE”子句中,“ WHEN MATCHED”不能多次出现?

党浩阔
2023-03-14
问题内容

我正在进行大量CRUD操作,并在CUD之外创建合并存储过程。我存储的过程看起来像这样

CREATE PROCEDURE usp_AdministrationHistoryMerge
    @AdministrationHistoryID int out,
    @AdministratorID int,
    @DateCreated datetime,
    @CreatedBy nvarchar(50),
    @ModifiedBy nvarchar(50),
    @Action int
AS

SET NOCOUNT OFF
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

DECLARE @ERROR_SEVERITY int,
        @MESSAGE varchar(1000),
        @ERROR_NUMBER int,
        @ERROR_PROCEDURE nvarchar(200),
        @ERROR_LINE int,
        @ERROR_MESSAGE nvarchar(4000),
        @IsActive bit,
        @DateModified datetime;
begin try
    if @Action = 1
        begin
            set @IsActive = 1
            set @AdministrationHistoryID = SCOPE_IDENTITY()
        end
    merge [AdministrationHistory] as target
    using (select @AdministratorID, @DateCreated, @CreatedBy, @DateModified, @ModifiedBy, @IsActive)
    as source (AdministratorID, DateCreated, CreatedBy, DateModified, ModifiedBy, IsActive)
    on (target.AdministrationHistoryID = source.AdministrationHistoryID)
    when matched and @Action = -1 then
        update
            set IsActive = 0
    when matched and @Action = 0 then
        update
        set ModifiedBy = @ModifiedBy,
        DateModified = GETDATE()
    when matched and @Action = 1 then
    insert
    (AdministratorID, DateCreated, CreatedBy, IsActive)
    values
    (@AdministratorID, @DateCreated, @CreatedBy, @IsActive);
end try

BEGIN CATCH
    SET @ERROR_SEVERITY = ISNULL(ERROR_SEVERITY(),'');
    SET @ERROR_NUMBER = ISNULL(ERROR_NUMBER(),'');
    SET @ERROR_PROCEDURE = ISNULL(ERROR_PROCEDURE(),''); 
    SET @ERROR_LINE = ISNULL(ERROR_LINE(),'');
    SET @ERROR_MESSAGE = ISNULL(ERROR_MESSAGE(),'');

    -- Test if the transaction is uncommittable.
    IF (XACT_STATE()) = -1
        BEGIN
            --PRINT N'The transaction is in an uncommittable state. Rolling back transaction.'
            ROLLBACK TRANSACTION;
        END;

    -- Test if the transaction is active and valid.
    IF (XACT_STATE()) = 1
        BEGIN
            --PRINT N'The transaction is committable. Committing transaction.'
            COMMIT TRANSACTION;   
        END;

    SET @MESSAGE = 'Error Occured in Stored Procedure ' + cast(@ERROR_PROCEDURE as varchar(200)) + 
                    '; Line Number ' + cast(@ERROR_LINE as varchar) + 
                    '; Message: [' + cast(@ERROR_NUMBER as varchar) + '] - '
                    + cast(@ERROR_MESSAGE as varchar(255))

    RAISERROR(@MESSAGE, @ERROR_SEVERITY, 1);
END CATCH;

当我执行此操作时,我得到了这个完整的错误

消息10714,级别15,状态1,过程usp_AdministrationHistoryMerge,第36行在MERGE语句的“
UPDATE”子句中,“ WHEN MATCHED”类型的动作不能出现多次。

我四处寻找SO,并找到了解决此问题的几种方法,但是我发现的解决方案并不适合此错误,因为不是删除,而是需要将记录的IsActive更新为0。

另外,在我的搜索中,没有人能真正解释为什么会引发此错误,是的,我知道它很明显,因为错误就在那里,但是为什么不允许这种错误发生呢?在这种情况下,关于如何实现这一点有什么想法吗?还是应该在@Act​​ion为0时让此合并调用另一个storedproc?


问题答案:

在您的MERGE陈述中,您有三个WHEN MATCHED子句

  • 两个有一个UPDATE声明
  • 一个INSERT声明。

但是,这是不允许的。在MERGE的文档中明确指出:

MERGE语句最多可以包含两个WHEN MATCHED子句。

如果有两个WHEN MATCHED子句,则一个子句必须指定一个UPDATE动作,另一个子句必须指定一个DELETE动作。

同样重要的是要知道:

如果UPDATE 子句中指定,并且 的多行与基于 的target_table中的一行匹配,则SQL
Server返回错误。该 MERGE语句不能多次更新同一行,也不能更新和删除同一行。



 类似资料:
  • 问题内容: 我必须在表target_table中插入/更新一些记录。这些记录是一个source_table。 我正在使用MERGE更新/插入target_table。 我想在更新中添加一些特定条件。 那么就应该只有更新,否则就没有更新或插入。 问题答案: 您可以简单地在中添加子句。在oracle docs中有更多关于它的信息。 因此,在您的情况下,它应如下所示:

  • 问题内容: 假设我有这个SQL查询: 如果我尝试执行此操作,则会收到一条错误消息,提示“ ISNULL附近的语法不正确”。我知道这是ISNULL的正确语法。为什么不能在CONTAINS语句内部调用ISNULL? 问题答案: 试试这个: 当您尝试将表达式放入存储过程调用时,这是相同的问题: CONTAIN需要字符串文字,请参见CONTAINS(Transact-SQL)

  • 问题内容: 我正在使用一条语句来添加新记录或更新当前记录。我有多个线程通过多个连接和多个语句(每个线程一个连接和一个语句)来驱动数据库。我一次要批处理50个语句。 我很惊讶在考试中遭到违反。我希望这是不可能的,因为将作为单个事务执行,或者是吗? 我的Java代码如下所示: 查询如下所示: 该错误显示为: 表格上的键是字段上的键。 问题答案: 是原子的,意味着所有更改都已提交或所有更改都已回滚。 在

  • 问题内容: 我已经习惯了MSSQL,而不是Mysql,所以对这个可能很愚蠢的问题感到抱歉。我正在尝试通过运行以下查询来更新备份数据库的密码: 当我运行它时,它说 查询正常,受影响的0行(0.01秒)匹配的行:1已更改:0警告:0 为什么行匹配但没有变化? 问题答案: 这意味着该值未更改。由于该列已等于的md5哈希值,因此可能未更改。

  • 问题内容: 为什么下面的代码: 给出错误: 在循环外继续 问题答案: 失败是switch语句的标准行为,因此,在switch语句中使用Continue没有意义。Continue语句仅在for / while / do..while循环中使用。 根据我对您意图的理解,您可能想写: 我还建议您将默认条件放在最后。 编辑:continue语句不能在switch语句中使用并不完全正确。(带有理想标记的)

  • 问题内容: 以下Java代码无法编译。 为什么?在没有先声明的情况下,没有代码路径可导致程序将1分配给该路径。 我想到的范围可能仅限于第一条陈述,但后来我不明白为什么。如果我真的不想不必要地声明以提高性能怎么办?我不喜欢声明后不使用变量。 (您可能想争论一下,我不可以在第二条语句中简单地声明b ,在这种情况下,请想象一下它可能在其他地方处于循环中。) 问题答案: 为什么?如果没有先声明,没有代码路