Как удалить остальные упорядоченные строки с одинаковым идентификатором после первой строки, которая встречается более одного раза с этим идентификатором? - PullRequest
0 голосов
/ 10 мая 2019

У меня есть следующая структура таблицы DataTable: каждый столбец имеет тип данных int, RowID - это столбец идентификаторов и первичный ключ. LinkID - это внешний ключ и ссылки на строки другой таблицы.

RowID   LinkID   Order  Data    DataSpecifier
1       120      1      1       1
2       120      2      1       3
3       120      3      1       10
4       120      4      1       13
5       120      5      1       10
6       120      6      1       13
7       371      1      6       2
8       371      2      3       5
9       371      3      8       1
10      371      4      10      1
11      371      5      7       2
12      371      6      3       3
13      371      7      7       2
14      371      8      17      4
.................................
.................................

Я пытаюсь выполнить запрос, который изменяет каждую партию LinkID следующим образом:

  • Взять каждую строку с одинаковым LinkID (например, первая партия - это первые 6 строк здесь)
  • Упорядочить их по столбцу Order
  • Посмотрите на столбцы Data и DataSpecifier как на одну единицу сравнения (их можно представить как один столбец, называемый dataunit):
  • Сохраняйте столько строк начиная с Order=1 и далее, до тех пор, пока не появится dataunit, который появляется более одного раза в партии
  • Сохранить эту последнюю строку, но удалить остальные строки с таким же LinkID и большим Order значением

Так что для LinkID 120:

  • Сортировка пакета по столбцу Order (уже отсортирована, но все равно должна это сделать)
  • Начните смотреть сверху (так что Order=1 здесь), продолжайте, пока вы не видите значение, которое появляется более 1 раза в партии
  • Остановка на первом дубликате Order=3 (dataunit 1 10 также включен Order 5).
  • Удалить все, что имеет LinkID=120 AND Order>=4

После аналогичного процесса для LinkID 371 (и всех остальных LinkID в таблице) обработанная таблица будет выглядеть следующим образом:

RowID   LinkID   Order  Data    DataSpecifier
1       120      1      1       1
2       120      2      1       3
3       120      3      1       10
7       371      1      6       2
8       371      2      3       5
9       371      3      8       1
10      371      4      10      1
11      371      5      7       2
.................................
.................................

Я никогда не выполнял SQL-запрос, который был бы сложным. Я знаю, что запрос должен быть примерно таким:

DELETE FROM DataTable  
WHERE RowID IN (SELECT RowID
                FROM DataTable
                WHERE -- ?
                GROUP BY LinkID
                HAVING COUNT(*) > 1 -- ?
                ORDER BY [Order]);

но я просто не могу обернуть голову вокруг этого и правильно понять запрос. Я бы предпочел сделать это на чистом SQL с одним исполняемым (и повторно используемым) запросом.


Я задал очень похожий вопрос: Как удалить остальные строки с одинаковым идентификатором, начиная с первого дубликата?

Но так как я понял, что моя исходная логика фильтрации в вопросе на самом деле не была тем, что мне было нужно, и на этот вопрос уже был дан правильный ответ, мне пришлось задать этот новый вопрос.

1 Ответ

2 голосов
/ 10 мая 2019

Здесь обновлено мое предыдущее решение.Несколько GROUP BY должно быть достаточно.Код достаточно прост для понимания.

Настройка:

IF OBJECT_ID('tempdb..#YourData') IS NOT NULL
    DROP TABLE #YourData

CREATE TABLE #YourData (
    RowID INT,
    LinkID INT,
    [Order] INT,
    Data INT,
    DataSpecifier INT)

INSERT INTO #YourData (
    RowID,
    LinkID,
    [Order],
    Data,
    DataSpecifier)
VALUES
    ('1', ' 120', '1', '1', ' 1'), 
    ('2', ' 120', '2', '1', ' 3'), 
    ('3', ' 120', '3', '1', ' 10'), 
    ('4', ' 120', '4', '1', ' 13'), 
    ('5', ' 120', '5', '1', ' 10'), 
    ('6', ' 120', '6', '1', ' 13'), 

    ('7', ' 371', '1', '6', ' 2'), 
    ('8', ' 371', '2', '3', ' 5'), 
    ('9', ' 371', '3', '8', ' 1'), 
    ('10', '371', '4', '10', '1'), 
    ('11', '371', '5', '7', ' 2'), 
    ('12', '371', '6', '3', ' 3'), 
    ('13', '371', '7', '7', ' 2'), 
    ('14', '371', '8', '17', '4')

Решение:

;WITH DuplicatesByLinkID AS
(
    SELECT
        Y.LinkID,
        Y.Data,
        Y.DataSpecifier,
        [Order] = MIN([Order])
    FROM
        #YourData AS Y
    GROUP BY
        Y.LinkID,
        Y.Data,
        Y.DataSpecifier
    HAVING
        COUNT(*) > 1
),
FirstDuplicateByLinkID AS
(
    SELECT
        D.LinkID,
        MinOrder = MIN(D.[Order])
    FROM
        DuplicatesByLinkID AS D
    GROUP BY
        D.LinkID
)
DELETE Y FROM
    #YourData AS Y
    INNER JOIN FirstDuplicateByLinkID AS M ON
        Y.LinkID = M.LinkID AND
        Y.[Order] > M.MinOrder

SELECT * FROM #YourData

Результат:

RowID   LinkID  Order   Data    DataSpecifier
1       120     1       1       1
2       120     2       1       3
3       120     3       1       10
7       371     1       6       2
8       371     2       3       5
9       371     3       8       1
10      371     4       10      1
11      371     5       7       2
...