尝试将表复制到另一个而不重复的错误

时间:2018-09-13 09:57:26

标签: sql sql-server tsql

基本上,我想将表 DET 复制到表 DET_NEW 。我知道 DET 有一些重复的行,所以我想只将重复的行插入一次。如您所见,我想使用 HDR 表按时间段复制这些行。

编辑以添加信息: DET 没有主键(这就是它具有重复行的原因)。 DET_NEW 具有包含 FK1 FK2 的复合主键。

问题:

我知道这不是一个新话题。我已经尝试了所有找到的解决方案,并且SQL Server返回了有关违反入门密钥约束的错误(“无法插入重复密钥”)。这些查询仅使用一个内核即可明确执行。

我看到MySQL具有INSERT IGNORE,但是我认为SQL Server中没有类似的东西。

我的解决方法如下:

查询1:

INSERT INTO DET_NEW
    (FK1, FK2, value)
SELECT DISTINCT D.FK1, D.FK2, D.value
FROM HDR AS H,
    DET AS D
WHERE H.Date  >= CONVERT( datetime, '2015-01-01 00:00:00', 20 )
    and H.Date < CONVERT( datetime, '2016-01-01 00:00:00', 20 ) 
    and H.FK1 = D.FK1

查询2:

INSERT INTO DET_NEW
    (FK1, FK2, value)
SELECT D.FK1, D.FK2, D.value
FROM 
(   SELECT DISTINCT D.FK1, D.FK2, D.value
    FROM HDR AS H,
        DET AS D
    WHERE H.Date  >= CONVERT( datetime, '2015-01-01 00:00:00', 20 )
        and H.Date < CONVERT( datetime, '2016-01-01 00:00:00', 20 ) 
        and H.FK1 = D.FK1
)D

查询3:

INSERT INTO DET_NEW
    (FK1, FK2, value)
SELECT D.FK1, D.FK2, D.value
FROM HDR AS H,
        DET AS D
    WHERE H.Date  >= CONVERT( datetime, '2018-02-01 00:00:00', 20 )
        and H.Date < CONVERT( datetime, '2018-02-05 00:00:00', 20 ) 
        and H.FK1 = D.FK1
GROUP BY D.FK1, D.FK2

查询4:

WITH cte AS (
    SELECT D.FK1, D.FK2, D.value,
        row_number() OVER(PARTITION BY D.FK1, D.FK2, D.value ORDER BY D.FK1) AS [rn]
    FROM HDR AS H,
        DET AS D
    WHERE H.Date  >= CONVERT( datetime, '2018-02-01 00:00:00', 20 )
        and H.Date < CONVERT( datetime, '2018-02-03 00:00:00', 20 ) 
        and H.FK1 = D.FK1
)

INSERT INTO DET_NEW
    (FK1, FK2, value)
SELECT cte.FK1, cte.FK2, cte.value
FROM cte
WHERE cte.[rn] = 1

其他信息

我执行了以下查询:在外部,代码检查是否存在重复;在内部,有一个SELECT DISTINCT,与查询2相同。结果超过1k行,因此查询中出现了一些错误。

SELECT D.FK1, D.FK2, COUNT(D.FK1) AS count
FROM (
    SELECT DISTINCT D.FK1, D.FK2, D.value
    FROM HDR AS H,
        DET AS D
    WHERE H.Date  >= CONVERT( datetime, '2018-02-01 00:00:00', 20 )
        and H.Date < CONVERT( datetime, '2018-02-03 00:00:00', 20 ) 
        and H.FK1 = D.FK1
    )D
GROUP BY D.FK1, D.FK2
HAVING 
    COUNT(*) > 1

问题是:为什么要插入重复项?大型数据库(数十亿行)还有另一种有效的方法吗?

2 个答案:

答案 0 :(得分:1)

INSERT INTO DET_NEW
    (FK1, FK2, value)   
SELECT  K.FK1, K.FK2, K.value
FROM
(SELECT D.FK1, D.FK2, D.value,
    ROW_NUMBER() OVER (PARTITION BY D.FK1, D.FK2 ORDER BY D.FK1, D.FK2) AS RN
FROM HDR AS H
    JOIN DET AS D ON H.FK1 = D.FK1
WHERE H.Date  >= CONVERT( datetime, '2015-01-01 00:00:00', 20 )
    and H.Date < CONVERT( datetime, '2016-01-01 00:00:00', 20 )) K
    WHERE K.RN=1

答案 1 :(得分:1)

对于1/NFK1的某些组合,FK2中可能有不止一个不同的value。以下查询应证明

DET

您将需要在SELECT FK1, FK2, MIN(value), MAX(value), COUNT(DISTINCT value) FROM DET GROUP BY FK1, FK2 HAVING COUNT(DISTINCT value) > 1 的复合键中包含值,或者确定如何选择每个键要使用的值,例如使用DET_NEWMIN。 @MoinulIslam提供的查询还将帮助您为每个键选择一个值。在该查询中,只是选择第一个。