Как преобразовать старые ограничения данных для того, чтобы исключить дублирование данных при сохранении ссылочной целостности - PullRequest
0 голосов
/ 01 марта 2012

PreNote: иначе мытье рук; это работа над проектом Brownfield


У меня есть таблица " ProductLine " следующим образом

| ProductLineID (pk) | ProductID (fk) | ResellerID (fk) | Other stuff |
|--------------------|----------------|-----------------|-------------|
| 1                  | 28             | 298818          |    --       |

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

Эти продуктовые линейки используются в таблице линия продажи , которая связана с таблицей продаж (которая связана с таблицей корзины).

Существует несколько таблиц, подключенных к производственным линиям по разным причинам.

То, на что я обращал внимание, - это создание дублированной копии продуктовых линеек и отбрасывание некоторых данных, так что будет создана только новая строка ЕСЛИ посредник внес изменение; таким образом, сокращая страницу с> 124 000 строк до 69 (никто не использовал функциональность в течение 5 лет).

Затем, используя в качестве справки старую таблицу ProductLine , изменяя существующие данные ( ProductLineId в таблице строк продажи), чтобы указать на новый ProductLineID , прочитав оригинальные строки ProductID и найдя новый совпадающий LineID (по одному на каждый продукт).

Мне было интересно, как лучше всего это сделать; на ум приходит курсор, но он стремится вывести DBA издалека с помощью вил, и мне, вероятно, потребуется выполнить аналогичный запрос для нескольких таблиц, поэтому чем менее болезненным будет SQL, тем лучше.

Просто чтобы сделать визуализацию немного проще, линия продажи выглядит следующим образом

| SaleLineId (pk) | SaleID (fk) | ProductLineId (fk) | Price |
|-----------------|-------------|--------------------|-------|
| 1992            | 29          | 10283              | 9.00  |

Extra

Я планирую переименовать старую таблицу ProductLine в LegacyProductLine. Затем dedupe + вставьте строки продуктов оттуда в чистую таблицу ProductLineTable.

Затем мне нужно заменить ProductLineId в SalesLine (и других) новым ProductLineId.

LegacyProductLine не будет знать, что такое ProductLineID в ProductLineTable; поэтому я рассматривал ProductID как способ их сопоставления, поскольку других подходящих параметров нет.



    +-----------------+     +-----------------+          +------------------+
    |LegacyProductLine|     | ProductLine     |          |  SaleLine        |
    |-----------------|     |-----------------|          |------------------|
    |ProductLineId PK |     | ProductLineID PK|          | SaleLineId    PK |
    |ProductName      |     | ProductName     |          | ProductLineId FK |
    |... some stuff   |     | ... Some stuff  |          | Charge           |
    |ResellerID  FK   |     |                 |          |                  |
    |ProductID FK     |     | ProductId       |          |                  |
    |                 |     |                 |          |                  |
    |                 |     |                 |          |                  |
    |                 |     |                 |          |                  |
    |                 |     |                 |          |                  |
    |                 |     |                 |          +------------------+
    |                 |     |                 |
    |                 |     |                 |
    |                 |     |                 |
    |                 |     |                 |
    +-----------------+     +-----------------+
     200K rows               26 Rows
     Mostly Duplicates       Deduped Data

Устаревшая таблица является временной только для справки и будет удалена. Мне нужно изменить ProductLineID в SaleLine Table .

Таблица SaleLine в настоящее время содержит ProductLineId из Legacy Table ; Их необходимо обновить, чтобы использовать ProductLineId в таблице ProductLine .

1 Ответ

1 голос
/ 01 марта 2012

Судя по всему, я не уверен, что вам даже нужна петля *. Вот мое предлагаемое решение, основанное на предположении ниже

Когда вы создаете свою новую таблицу ProductLine (PL) с дуплицированными данными, вам нужно будет создать таблицу отображения из NewPL в OldPL (Map_OldPL_NewPL). Это делает проблему тривиальной:

UPDATE SalesLine
SET PLId = NewPLId
FROM SalesLine
    JOIN Map_OldPL_NewPL AS Map
        ON SalesLine.PLId = OldPLId

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

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

UPDATE:

Вот полный ответ. Вероятно, вы могли бы сделать все это в пределах одного или двух запросов, но таким образом вы всегда можете иметь таблицу сопоставления для просмотра. Я предполагаю, что это дубликат, если все, кроме PK (ProductLineId) одинаковы. Если нет, то вам нужно изменить раздел ROW_NUMBER и следующее обновление.

CREATE TABLE DuplicateMapping
(
    OldProductLineId INT, 
    ProductName VARCHAR(MAX), 
    ... , 
    ResellerId INT, 
    ProductId INT
    DuplicateHierarchy INT,
    NewProductLineId INT
)

INSERT INTO DuplicateMapping
SELECT  ProductLineId AS OldProductLineId, ProductName, ... , ResellerId, ProductId, 
    ROW_NUMBER() OVER 
        (PARTITION BY ProductName, 
            ... , ResellerId, ProductId ORDER BY ProductLineId) AS DuplicateHierarchy,
    ProductLineId AS NewProductLineId
FROM ProductLine

UPDATE DuplicateMapping
SET NewProductLineId = Dup.OldProductLine
FROM DuplicateMapping AS Main
    JOIN DuplicateMapping AS Dup
        ON DuplicateMapping.ProductName = Dup.ProductName
            AND DuplicateMapping.ResellerId = Dup.ResellerId
            AND DuplicateMapping.ProductId = Dup.ProductId
            ...
            --Do NOT include OldProductLineId, NewProductLineId or DuplicateHierarchy
WHERE Dup.DuplicateHierarchy = 1

DELETE ProductLine
WHERE EXISTS 
(
    SELECT 1 
    FROM DuplicateMapping
    WHERE DuplicateMapping.ProductLineId = ProductLine.ProductLineId
        AND DuplicateMapping.DuplicateHierarchy > 1
)

UPDATE SaleLine
SET ProductLineId = NewProductLineId
FROM SaleLine
    JOIN DuplicateMapping
        ON ProductLineId = OldProductLineId
--Without this, you would not cause any harm
--Howerver, why update the same value over itself 
WHERE DuplicateHierarchy > 1
...