【问题标题】:How to solve violation of primary key cannot insert duplicate values error in SQL Server?如何解决 SQL Server 中主键冲突不能插入重复值错误?
【发布时间】:2017-02-24 14:22:11
【问题描述】:

我对我的Order Details 表执行了以下查询,该表旨在复制OrderDetai11 中的所有记录

insert into [dbo].[Order Details] (OrderID,ProductID,UnitPrice,Quantity,Discount) 
select OrderID,ProductID,UnitPrice,Quantity,Discount 
from[dbo].[Order Detai11] as OD1 
where OD1. OrderID between 1 and 150000;

我收到以下错误

消息 2627,级别 14,状态 1,第 1 行违反主键 约束“PK_Order_Details”。无法在对象中插入重复键 'dbo. 订单详情'。重复键值为 (10248, 11)。这 语句已终止。

【问题讨论】:

    标签: sql sql-server primary-key sql-insert


    【解决方案1】:

    假设 [Order Details] 是 [Order Detail11] 的副本。您只想插入或更新您的记录:您可以使用 MERGE (what is a MERGE? here),例如:

    MERGE [dbo].[Order Details]
    USING ( select OrderID,ProductID,UnitPrice,Quantity,Discount 
            from[dbo].[Order Detai11]
            where OrderID between 1 and 150000 
        ) As tblMergeDetail(OrderID,ProductID,UnitPrice,Quantity,Discount)
    ON (    tblMergeDetail.OrderId = [dbo].[Order Details].OrderId  )
    WHEN MATCHED THEN
    SET ProductID = tblMergeDetail.ProductID,
        UnitPrice = tblMergeDetail.UnitPrice,
        Quantity = tblMergeDetail.Quantity,
        Discount = tblMergeDetail.Discount
    WHEN NOT MATCHED THEN
    INSERT (OrderID,ProductID,UnitPrice,Quantity,Discount)
    VALUES (
        tblMergeDetail.OrderID,
        tblMergeDetail.ProductID,
        tblMergeDetail.UnitPrice,
        tblMergeDetail.Quantity,
        tblMergeDetail.Discount
    );
    

    如果您只想复制不存在的记录,您可以排除 [Order Details] 中的值,例如:

    insert into [dbo].[Order Details] 
    (OrderID,ProductID,UnitPrice,Quantity,Discount) 
    select OrderID,ProductID,UnitPrice,Quantity,Discount
    from[dbo].[Order Detai11] as OD1 
    where OD1.OrderID between 1 and 150000
    and NOT EXISTS (    select  exclusionTbl.OrderID
                        from    [dbo].[Order Details] exclusionTbl
                        where   exclusionTbl.OrderID = OD1.OrderID
                    )
    

    编辑:

    另一个例子:

    insert into [dbo].[Order Details] 
    (OrderID,ProductID,UnitPrice,Quantity,Discount) 
    select OrderID,ProductID,UnitPrice,Quantity,Discount
    from[dbo].[Order Detai11] as OD1 
    where OD1.OrderID between 1 and 150000
      and OD1.OrderID NOT IN(   select  exclusionTbl.OrderID
                                from    [dbo].[Order Details] exclusionTbl
                                where   exclusionTbl.OrderID between 1 and 150000
                            )
    

    对于 NOT EXISTS 查询:我们检查在 [Order Details] 中不存在我们想要从 [OrderDetai11] 插入的 OrderID

    对于 NOT IN 查询:我们检查所有 [OrderDetai11].OrderIDs,没有人包含在 [Order Details].OrderID 列表中。它实现了与 NOT EXISTS 查询相同的结果。

    【讨论】:

    • 搞定了..这里很好..你能解释一下第二个查询中不存在的部分吗
    • At first you need to know what a PRIMARY KEY is. 如果您确实理解了这一点,那么您现在知道为什么会出现错误:“违反 PRIMARY KEY 约束”。我在第二个查询中的条件是永远不会触发您的密钥(OrderID)的重复。
    • Arg 我刚刚意识到我假设 OrderID 是您的主键。那是对的吗?否则我的两个答案都完全错了。
    • 是的。主键是 OrderID,merge 是我会研究的。
    • 也许我不是很清楚,但 MERGE 解决方案与其他 2 个解决方案不同,因为它会更新您以前的记录。 (也可用于删除而不是更新。)其他 2 将仅添加 [Order Details] 中不存在的行。选择最适合您需要的。
    【解决方案2】:

    您正在尝试将具有相同主键的记录插入到新表中。

    你需要确保原表没有重复记录,大概你的主键是OrderID

    您可以通过在原始表上使用此选择查询来检查这一点:

    SELECT OrderID, COUNT(OrderID) AS Total
    FROM [dbo].[Order Detai11] 
    GROUP BY OrderID
    ORDER BY Total DESC
    

    如果total 列中有任何包含 2 或更多行的行,则说明存在重复。

    您需要删除重复项,或者如果要保留它们,则需要在新表中创建一个新列并将其设为主键。

    cmets 之后:

    您的原始表可能没有主键,或者如果有,则说明您没有将其正确复制到新表中。

    除非您执行以下操作之一,否则这将无法正常工作:

    • 创建一个新列并将其设为主键。
    • 使用复合主键(由多个列组成的主键)。
    • 删除OrderID作为主键。

    【讨论】:

    • 大部分列都有重复项,我需要插入所有列,此外我的列名对于两个表都相同
    【解决方案3】:

    只需确保目标表没有重复项即可。如果源表有重复,请确保只获取不同的记录。

    /******  REMOVE DUPLICATES ******/
    
     WITH CTE AS(
       SELECT *,
           RN = ROW_NUMBER()OVER(PARTITION BY OrderId ORDER BY OrderId)
       FROM [dbo].[Order Details]
    )
    DELETE FROM CTE WHERE RN > 1
    
    /****** Script for merging after removing duplicates from destination table  ******/
    
    BEGIN
    WITH dedupe AS (SELECT DISTINCT OrderID,ProductID,UnitPrice,Quantity,Discount 
    from[dbo].[Order Detai11])
    MERGE [dbo].[Order Details]
    USING dedupe AS tblMergeDetail
    ON (    tblMergeDetail.OrderId = [dbo].[Order Details].OrderId  )
    WHEN MATCHED THEN
    SET ProductID = tblMergeDetail.ProductID,
        UnitPrice = tblMergeDetail.UnitPrice,
        Quantity = tblMergeDetail.Quantity,
        Discount = tblMergeDetail.Discount
    WHEN NOT MATCHED THEN
    INSERT (OrderID,ProductID,UnitPrice,Quantity,Discount)
    VALUES (
        tblMergeDetail.OrderID,
        tblMergeDetail.ProductID,
        tblMergeDetail.UnitPrice,
        tblMergeDetail.Quantity,
        tblMergeDetail.Discount
    );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-20
      • 1970-01-01
      • 2011-04-22
      相关资源
      最近更新 更多