【问题标题】:Is there a way to tell SQL Server to check the table for a duplicate before inserting each new row?有没有办法告诉 SQL Server 在插入每个新行之前检查表中的重复项?
【发布时间】:2020-09-21 06:10:42
【问题描述】:

我尝试使用下面的 SQL 将值从一个表 importTable 插入到另一个表 POInvoicing。看来,下面这个查询的工作方式是检查POInvoicing 表中是否存在来自importTable 的任何可能重复项,对于那些不重复的条目,它将它们插入表中。最终结果是 SQL 插入 importTable 中已存在的重复项。有没有办法告诉 SQL Server 检查表中是否存在可能的重复条目,如果没有,请添加下一行。然后检查表中是否有重复条目,如果没有,请添加下一行。我知道这会慢一些,但速度不是问题。

INSERT INTO POInvoicing 
    (VendorID, InvoiceNo) 
SELECT dbo.importTable.VendorID,
       dbo.importTable.InvoiceNo
  FROM dbo.importTable
WHERE NOT EXISTS (SELECT VendorID,
                         InvoiceNo
                    FROM POInvoicing
                   WHERE POInvoicing.VendorID = dbo.importTable.VendorID AND
                         POInvoicing.InvoiceNo = dbo.importTable.InvoiceNo)

这并不是我所希望的功能。我想要的是查询在表中插入一行,然后在插入下一行之前检查“重复”。 importTable 中的重复项是 VendorID 和 InvoiceNo 的组合。 importTable 中有大约十几个不同的列,从技术上讲,每一行都是不同的,所以 DISTINCT 在这里不起作用。

由于与上述问题无关的几个原因,我不能简单地从 importTable 中删除重复项(尽管我可以在必要时提供),因此该方法已失效。

【问题讨论】:

  • 仅供参考,不推荐使用列中的 3 部分命名,并且可以在 SQL Server 的未来版本中删除。建议您为表设置别名,然后使用表的别名限定列。
  • 因此,如果您在importTable 中有两行(例如VendorID = 5, InvoiceNo = 10)并且它们对于InvoiceDate 有两个不同的值(或相同的值),您如何确定哪一个不是副本?
  • @AaronBertrand 使importTable 中的每一行不同的是POInvoicing 表不关心并且不会添加到POInvoicing 表中的杂项数据。另一方面,我们的POInvoicingDetails 表确实关心那些额外的数据并将利用它。为了简单起见,我想我可以进一步减少查询。实际上,不会有两个 VendorID = 5、InvoiceNo = 10 的条目具有两个不同的 EntryDate。
  • 您可以使用 MERGE 语句并且只处理带有 WHEN NOT MATCHED BY TARGET 部分的 INSERT?
  • @JonathanLarouche 我不认为MERGE 是这里需要的(它仍然会为NOT MATCHED 返回多行)和I wouldn't recommend it generally even if it were

标签: sql-server insert duplicates


【解决方案1】:

如果您真的不关心(或拒绝告诉我们)您想如何在具有相同 VendorIDInvoiceNo 值的两行之间做出决定,您可以像这样选择任意一行:

;WITH NewRows AS
(
  SELECT VendorID, InvoiceNo, InvoiceDate, /* ... other columns ... */
    rn = ROW_NUMBER() OVER (PARTITION BY VendorID, InvoiceNo ORDER BY (SELECT NULL))
  FROM dbo.importTable AS i
  WHERE NOT EXISTS (SELECT 1 FROM dbo.POInvoicing AS p
                      WHERE p.VendorID = i.VendorID
                      AND p.InvoiceNo = i.InvoiceNo)
)
INSERT dbo.POInvoicing(VendorID, InvoiceNo, InvoiceDate /* , ... other columns ... */)
  SELECT VendorID, InvoiceNo, InvoiceDate /* , ... other columns */
  FROM NewRows
  WHERE rn = 1;

如果您稍后决定在重复的情况下需要特定的行,则可以将 (SELECT NULL) 换成其他内容。例如,获取发票日期最新的行:

OVER (PARTITION BY VendorID, InvoiceNo ORDER BY InvoiceDate DESC)

再一次,我在这里问问题并不是为了让您烦恼,而是为了帮助您获得所需的解决方案。如果您希望 SQL Server 在两个重复项之间进行选择,您可以告诉它如何选择,或者您必须接受任意/不确定的结果。你不应该仅仅因为你尝试的第一件事没有按照你想要的方式工作,就跳过栅栏循环/游标。

还有please always specify the schemause sensible table aliases

【讨论】:

    【解决方案2】:

    在表中添加主键约束唯一键约束以避免重复数据插入。

    还要在您的选择查询中使用 distinct 关键字来避免这种情况。

    也可以使用 SQL 中的 group byrow_number() 函数消除重复行。

    使用 DISTINCT 关键字

     INSERT INTO POInvoicing 
     (VendorID, InvoiceNo, InvoiceDate) 
     SELECT DISTINCT dbo.importTable.VendorID,
       dbo.importTable.InvoiceNo,
       dbo.importTable.InvoiceDate 
      FROM dbo.importTable
     WHERE NOT EXISTS (SELECT VendorID,
                         InvoiceNo
                    FROM POInvoicing
                   WHERE POInvoicing.VendorID = dbo.importTable.VendorID 
     AND
                         POInvoicing.InvoiceNo = dbo.importTable.InvoiceNo)
    

    试试这个INNER JOIN

     INSERT INTO POInvoicing 
     (VendorID, InvoiceNo, InvoiceDate) 
     SELECT dbo.importTable.VendorID,
       dbo.importTable.InvoiceNo,
       dbo.importTable.InvoiceDate 
      FROM dbo.importTable IM
      INNER JOIN POInvoicing S ON S.POInvoicing.VendorID <> 
      dbo.importTable.VendorID 
     AND
                         S.POInvoicing.InvoiceNo <> dbo.importTable.InvoiceN
    

    【讨论】:

    • 这行不通。我想我需要稍微修改一下我的帖子。 importTable 中有很多列,而不仅仅是三个。所以从技术上讲,每一行都是不同的。我想告诉 SQL,为了这个 INSERT 查询,与众不同的地方仅基于 VendorIDInvoiceNo 的独特组合。
    • 试试这个内部连接查询。我想这会帮助你 --@JohnCoolidge
    • 分享你的 cmets -- @John Coolidge
    • @JohnCoolidge 如果您有两列的组合“使某些东西与众不同”,那么您需要告诉 SQL Server 当有多个行时您想要哪一行。您可能不在乎得到哪一行,但 SQL Server 需要以某种方式打破平局。向我们展示一些实际数据(这两列具有相同的值以及其他列的一些实际值),并告诉我们您要保留/插入哪一行以及为什么。没有细节,我们无能为力。
    • @AaronBertrand 所以,我从中收集到的是,没有办法让 SQL Server 在插入每一行之前检查整个表。因为这足以告诉 SQL Server 下一个插入是重复的。我知道这会非常慢,但是对于我正在做的事情,这该死的事情可能需要一个小时,这并不重要,因为这个查询将在没有人访问 SQL Server 的晚上运行。
    猜你喜欢
    • 1970-01-01
    • 2012-03-28
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 2014-06-27
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    相关资源
    最近更新 更多