You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MERGE语句报错:同一行被多次更新/删除问题求助

问题分析与解决方案

错误原因

  1. 跨库Object_ID不唯一:SQL Server中object_id仅在单个数据库内唯一,不同数据库的存储过程可能拥有相同的object_id。你当前的MERGE仅用Object_ID作为匹配条件,会导致不同数据库的同ID存储过程匹配到目标表的同一行,触发重复更新/插入的错误。
  2. 源数据存在重复行:sys.dm_exec_procedure_stats会为存储过程的每个缓存执行计划返回一行,同一存储过程可能对应多条记录,导致源数据中出现同一(DataBaseName, Object_ID)的重复条目,MERGE时会试图多次更新同一目标行。

修正后的存储过程

ALTER PROCEDURE [dbo].[ProcedureUsageStats]
AS
BEGIN
    DECLARE @command NVARCHAR(MAX)

    SET @command = '
    USE [?];
    MERGE [Db1].[dbo].[table1] AS target
    USING (
        SELECT 
            db_name() AS DataBaseName,
            v.object_id AS Object_ID,
            v.name AS StroredProcName,
            v.create_date,
            v.modify_date,
            -- 取同一存储过程的最新执行时间
            MAX(ps.last_execution_time) AS LastExecutionTime,
            v.type,
            v.type_desc
        FROM 
            sys.procedures v
        LEFT JOIN 
            sys.dm_exec_procedure_stats ps
            ON v.object_id = ps.object_id
            -- 限定DMV的数据库范围,避免跨库匹配
            AND ps.database_id = DB_ID()
        -- 按存储过程唯一标识分组,确保每个存储过程只返回一行
        GROUP BY 
            db_name(), v.object_id, v.name, v.create_date, v.modify_date, v.type, v.type_desc
    ) AS source
    -- 改用联合键作为匹配条件,确保唯一匹配
    ON (target.DataBaseName = source.DataBaseName AND target.Object_ID = source.Object_ID)

    -- 目标表无匹配行则插入
    WHEN NOT MATCHED BY TARGET THEN
        INSERT ([DataBaseName], [Object_ID], [StroredProcName], [create_date], [modify_date], [LastExecutionTime], [type], [type_desc])
        VALUES (source.DataBaseName, source.Object_ID, source.StroredProcName, source.create_date, source.modify_date, source.LastExecutionTime, source.type, source.type_desc)

    -- 目标表有匹配行且源数据有最新执行时间则更新
    WHEN MATCHED AND source.LastExecutionTime IS NOT NULL THEN
        UPDATE SET 
            target.LastExecutionTime = source.LastExecutionTime,
            -- 可选:同步存储过程的最新修改时间
            target.modify_date = source.modify_date;
    '

    EXEC sp_MSforeachdb @command;
END;

关键修改点

  • 联合匹配键:MERGE的ON条件改为target.DataBaseName = source.DataBaseName AND target.Object_ID = source.Object_ID,确保每个目标行唯一对应单个数据库的单个存储过程。
  • 源数据去重:通过GROUP BY聚合同一存储过程的记录,用MAX(ps.last_execution_time)获取最新的执行时间,避免源数据重复。
  • 限定DMV范围:在sys.dm_exec_procedure_stats的关联条件中加入ps.database_id = DB_ID(),避免误匹配其他数据库的缓存计划。

内容的提问来源于stack exchange,提问作者Immortal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 19:07:03