【问题标题】:Why would a SQL MERGE have a duplicate key error, even with HOLDLOCK declared?为什么即使声明了 HOLDLOCK,SQL MERGE 也会出现重复键错误?
【发布时间】:2013-11-26 22:37:08
【问题描述】:

我可以在 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 锁吗?

【问题讨论】:

  • 我的建议:用老方法做。 MERGE 可能看起来不错,但它有很多问题。 mssqltips.com/sqlservertip/3074/…
  • 表的定义是什么?它有不止一个独特的约束吗?来源是否也有重复?
  • SQL 语句“并行”有效地应用所有行更改 - 如果源表中有两行具有相同的 PK 值,而目标中没有具有该 PK 值的行,MERGE将尝试插入 两行 行,然后失败。
  • @AaronBertrand 我害怕那个。稍后我会试一试并发布结果。
  • 不,你错了。 HOLDLOCK 在这里只是防止在检查行不存在和尝试插入之间的 不同 事务中插入行。它不会对源中的任何重复键进行重复数据删除。如果有多个具有相同的t2.id,您要插入哪一行?

标签: sql-server-2008 merge


【解决方案1】:

我找到了解决问题的方法,并想在此处发布答案,以防对其他人有所帮助。看起来 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    • 2015-03-08
    • 2021-09-20
    • 1970-01-01
    • 2011-10-31
    相关资源
    最近更新 更多