Ошибка при попытке скопировать таблицу в другую без дубликатов - PullRequest
0 голосов
/ 13 сентября 2018

В основном я хочу скопировать таблицу DET в таблицу DET_NEW .Я знаю, что DET имеет несколько дублированных строк, поэтому я хочу сделать это, вставляя дублированные строки только один раз.Как видите, я хочу скопировать эти строки по периодам, используя HDR таблицу.

Изменить, чтобы добавить информацию: DET не имеет первичных ключей (поэтому он имеетдублированные строки). DET_NEW имеет составной первичный ключ с FK1 и FK2 .

ПРОБЛЕМА:

IЗнаю, что это не новая тема.Я перепробовал все найденные решения, и 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, такой же, как Query 2. Результаты более 1 тыс. строк, поэтому в запросах есть что-то неверное.

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

Вопросы: Почему я вставляю дубликаты?Есть еще один эффективный способ для большой базы данных (миллиарды строк)?

Ответы [ 3 ]

0 голосов
/ 13 сентября 2018
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
0 голосов
/ 13 сентября 2018

Вероятно, что для некоторых комбинаций FK1 и 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_NEW, либо решить, как вы хотите выбрать, какое значение использовать для каждого ключа, например, используя MIN или MAX. Запрос, предоставленный @MoinulIslam, также поможет вам выбрать одно значение для каждого ключа. В этом запросе он просто выбирает первый.

0 голосов
/ 13 сентября 2018

Поскольку вы разделяете вставку, отличное действие действует только на «текущий фрагмент», и я подозреваю, что поэтому оно вставляет строку со значением, которое уже существует, отсюда и нарушение ограничения PK.Вы действительно должны предоставить в своем вопросе подробности о том, каков состав первичного ключа, но я предполагаю, что он представляет собой совокупность из 3 полей fk1, fk2 и value.

Возможно, а не разбивку по дате, чтопредположительно не имеет никакого отношения к значениям, включенным в FK1, FK2 и value, вы можете упорядочить ваш «входящий» набор данных по этим полям, гарантируя, что все возможные дубликаты будут храниться в вашем «входящем фрагменте», чтобы различные могли работать с ним.

Итак, я бы выбрал одно из полей, которое даст вам наилучшую производительность, и использовал бы вот так:

Create table #tt(
 fk1 fk1_datatype null
)

insert #tt(fk1)
select distinct fk1
from DET
order by fk1

<< while clause to get next value from #tt and read into @fk1>>

INSERT INTO DET_NEW
(FK1, FK2, value)
SELECT distinct FK1, FK2, value
FROM DET AS D
WHERE D.FK1 = @fk1

<< end of while clause removing @fk1 from #tt >>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...