为什么SQL MERGE会出现重复键错误,即使已声明HOLDLOCK?

时间:2013-11-18 14:31:42

标签: sql-server-2008 merge

我可以在SQL Merge上找到很多信息,但我似乎无法让这对我有用。这就是发生的事情。

每天我都会将Excel文件上传到具有几千条记录的Web服务器,每条记录包含180列。这些记录包含必须使用INSERT的新信息和必须使用UPDATE的更新信息。为了获取数据库的信息,我正在使用C#批量复制到临时SQL 2008表。我的计划是然后执行合并以将信息输入到实时表中。临时表没有主键集,但是实时表没有。最后,这就是我的Merge语句的外观:

MERGE Table1 WITH (HOLDLOCK) AS t1
USING (SELECT * FROM Table2) AS t2
ON t1.id = t2.id
WHEN MATCHED THEN
    UPDATE SET (t1.col1=t2.col1,t1.col2=t2.col2,...t1.colx=t2.colx)
WHEN NOT MATCHED BY TARGET THEN
    INSERT (col1,col2,...colx)
    VALUES(t2.col1,t2.col2,...t2.colx);

即使包含HOLDLOCK,我仍然会收到错误Cannot insert duplicate key in object。从我在线阅读的内容来看,HOLDLOCK应该允许SQL读取主键,但是在执行任务之前不执行任何插入或更新。我基本上是在学习如何动态使用MERGE,但我是否需要为SQL 2008启用MERGE Locks?

1 个答案:

答案 0 :(得分:2)

我找到了解决问题的方法,并希望在这里发布答案,以防它帮助其他人。看起来MERGE不能用于我需要的东西,因为使用的临时表具有将用作实时表中的主键的重复记录。我想出的解决方案是创建以下存储过程。

    -- Start with insert
    INSERT INTO LiveTable(A, B, C, D, id)
    (
    -- Filter rows to get unique id
    SELECT A, B, C, D, id FROM(
        SELECT A, B, C, D, id,
                ROW_NUMBER() OVER (PARTITION BY id ORDER BY id) AS row_number
        FROM TempTable
        WHERE NOT EXISTS(
    SELECT id FROM LiveTable WHERE LiveTable.id = TempTable.id)
        ) AS ROWS
    WHERE row_number = 1
    )

-- Continue with Update
-- Covers skipped id's during insert
UPDATE tb_TestMLS
SET
    LiveTable.A = T.A,
    LiveTable.B = T.B,
    LiveTable.C = T.C,
    LiveTable.D = T.D
FROM LiveTable L
INNER JOIN
    TempTable T
ON
    L.id= T.id