Мне интересно, как лучше всего переносить мои данные при разбиении таблицы на многие отношения. Я сделал упрощенный пример, и я также опубликую некоторые из решений, которые я придумал. Я использую базу данных Postgresql.
Перед миграцией
Персонал таблицы
ID Name Pet PetName
1 Follett Cat Garfield
2 Rowling Hamster Furry
3 Martin Cat Tom
4 Cage Cat Tom
После миграции
Персонал таблицы
ID Name
1 Follett
2 Rowling
3 Martin
4 Cage
Таблица Pet
ID Pet PetName
6 Cat Garfield
7 Hamster Furry
8 Cat Tom
9 Cat Tom
Таблица PersonPet
FK_Person FK_Pet
1 6
2 7
3 8
4 9
Примечания:
- Я буду дублировать записи в таблице домашних животных (потому что в моем случае - из-за других связанных данных - один из них может быть доступен для редактирования клиентом, а другой - нет).
- Нет столбца, который однозначно идентифицирует запись "Pet".
- Для меня неважно, связаны ли 3-8 и 4-9 в таблице PersonPet или 3-9 и 4-8.
- Также я пропустил весь код, который обрабатывает изменения схемы таблиц, поскольку это - в моем понимании - нерелевантно для этого вопроса.
Мои решения
- При создании таблицы Pet временно добавьте столбец, содержащий идентификатор таблицы Person, который использовался для создания этой записи.
ALTER TABLE Pet ADD COLUMN IdPerson INTEGER;
INSERT INTO Pet (Pet, PetName, IdPerson)
SELECT Pet, PetName, ID
FROM Person;
INSERT INTO PersonPet (FK_Person, FK_Pet)
SELECT ID, IdPerson
FROM Pet;
ALTER TABLE Pet DROP Column IdPerson;
- избежать временного изменения таблицы домашних животных
INSERT INTO Pet (Pet, PetName)
SELECT Pet, PetName
FROM Person;
WITH
CTE_Person
AS
(SELECT
Id, Pet, PetName
,ROW_NUMBER() OVER (PARTITION BY Pet, PetName ORDER BY Id) AS row_number
FROM Person
)
,CTE_Pet
AS
(SELECT
Id, Pet, PetName
,ROW_NUMBER() OVER (PARTITION BY Pet, PetName ORDER BY Id) AS row_number
FROM Pet
)
,CTE_Joined
AS
(SELECT
CTE_Person.Id AS Person_Id,
CTE_Pet.Id AS Pet_Id
FROM
CTE_Person
INNER JOIN CTE_Pet ON
CTE_Person.Pet = CTE_Pet.Pet
CTE_Person.PetName = CTE_Pet.PetName
AND CTE_Person.row_number = CTE_Pet.row_number
)
INSERT INTO PersonPet (FK_Person, FK_Pet)
SELECT Person_Id, Pet_Id from CTE_Joined;
Вопросы
- Правильны ли оба решения? (Я тестировал второе решение, и результат кажется правильным, но я, возможно, пропустил какой-то угловой случай)
- Каковы преимущества/недостатки двух решений?
- Есть ли более простой способ сделать одну и ту же миграцию данных? (Для моего любопытства меня также интересовали бы ответы, которые немного меняют мои ограничения (например, никаких дубликатов записей в таблице домашних животных), но укажите, какие из них:)).