【问题标题】:SQL Merge from staging table causing duplicate rows临时表中的 SQL 合并导致重复行
【发布时间】:2020-09-02 16:51:47
【问题描述】:

我有一个 SQL Server 存储过程,它在一个临时表和几个目标表之间移动数据。有一个表,我正在尝试更新两列,这些列标识最初标记某事物的时间和最后一次标记的时间。表是这样定义的

MyStaging表:

STAGING_ROW_ID*     FILE_DATETIME              IMPORT_ID       UPDATE_ID       COMPUTER_IP
    1              '2020-08-27 11:44:47.000'     1            100-1           192.168.100.1
    2              '2020-08-31 12:15:48.000'     1            100-1           192.168.100.1
    3              '2020-08-31 12:30:10.000'     1            100-2           192.168.100.2

MyTable表:

UPDATE_ID*    COMPUTER_IP*       FIRST_DATE_FLAGGED    LAST_DATE_FLAGGED     TOTAL_NUMBER
  100-1       192.168.100.1    2020-08-27 11:44:47.000  2020-08-31 12:15:48.000       2
  100-2       192.168.100.2    2020-08-31 12:30:10.000  2020-08-31 12:30:10.000       1

*星号表示主键

在合并期间,我正在尝试这样做:

MERGE INTO dbo.MyTable mt 
USING (SELECT UPDATE_ID, COMPUTER_IP, FILE_DATETIME, COUNT(*) AS TOTAL_NUMBER
       FROM dbo.MyStaging
       WHERE "IMPORT_ID" = @importID
       GROUP BY UPDATE_ID, COMPUTER_IP, FILE_DATETIME) ms ON mt.UPDATE_ID = ms.UPDATE_ID
                                                          AND mt.COMPUTER_IP = ms.COMPUTER_IP

WHEN MATCHED THEN  
    UPDATE 
        SET
            mt.TOTAL_NUMBER = mt.TOTAL_NUMBER + ms.TOTAL_NUMBER, 
            mt.LAST_DATE_FLAGGED = CASE WHEN ms.FILE_DATETIME > mt.LAST_DATE_FLAGGED
                                           THEN ms.FILE_DATETIME 
                                           ELSE mt.LAST_DATE_FLAGGED 
                                   END

WHEN NOT MATCHED THEN 
    INSERT (UPDATE_ID, COMPUTER_IP, FIRST_DATE_FLAGGED, LAST_DATE_FLAGGED, TOTAL_NUMBER)
    VALUES (ms.UPDATE_ID, ms.COMPUTER_IP, ms.FILE_DATETIME, ms.FILE_DATETIME, ms.TOTAL_NUMBER);

我知道这不是正确的方法。我收到一个错误,因为 FILE_DATETIME 列会导致一些重复。由于UPDATE_IDCOMPUTER_IPMyTable 中的复合键,并且FILE_DATETIME 会有多个条目,这是可以理解的。

我的问题是如何更改我的合并以获取这些日期,同时仍然只获取适当的列?在更新语句中,我只需要更新LAST_DATE_FLAGGED 列。在插入中,我只需要将最晚日期同时作为第一个日期和最后一个日期。

【问题讨论】:

  • 需求不明确。您想更新LAST_DATE_IDENTIFIED,但您正在更新LAST_DATE_FLAGGED。如果有多个更新应该考虑哪一行?什么是 count(*) 基于?
  • 抱歉,列名以“FLAGGED”结尾。已编辑。
  • 正如我所问的,如果有多个值要更新为 LAST_DATE_FLAGGED 和 count(*) 作为复合键或包括日期?
  • LAST_DATE_FLAGGED 应该是该特定复合键的最新日期。
  • 请阅读MERGE with caution - 也许您的批次还有更多内容,但如果您没有使用正确的锁定/隔离,肯定会出现问题。

标签: sql sql-server merge


【解决方案1】:

如果我理解正确,您可以将 using 子句更改为使用MAX 来获取最新的日期数据,

MERGE INTO dbo.MyTable mt 
USING (SELECT UPDATE_ID, COMPUTER_IP, MAX(FILE_DATETIME) AS FILE_DATETIME, COUNT(*) AS TOTAL_NUMBER
       FROM dbo.MyStaging
       WHERE "IMPORT_ID" = @importID
       GROUP BY UPDATE_ID, COMPUTER_IP) ms ON mt.UPDATE_ID = ms.UPDATE_ID
                                                          AND mt.COMPUTER_IP = ms.COMPUTER_IP

WHEN MATCHED THEN  
    UPDATE 
        SET
            mt.TOTAL_NUMBER = mt.TOTAL_NUMBER + ms.TOTAL_NUMBER, 
            mt.LAST_DATE_FLAGGED = CASE WHEN ms.FILE_DATETIME > mt.LAST_DATE_FLAGGED
                                           THEN ms.FILE_DATETIME 
                                           ELSE mt.LAST_DATE_FLAGGED 
                                   END

WHEN NOT MATCHED THEN 
    INSERT (UPDATE_ID, COMPUTER_IP, FIRST_DATE_FLAGGED, LAST_DATE_FLAGGED, TOTAL_NUMBER)
    VALUES (ms.UPDATE_ID, ms.COMPUTER_IP, ms.FILE_DATETIME, ms.FILE_DATETIME, ms.TOTAL_NUMBER);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-28
    • 2014-09-08
    • 2020-10-30
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 2015-04-11
    • 1970-01-01
    相关资源
    最近更新 更多