TSQL: ОБНОВЛЕНИЕ с INSERT INTO ВЫБРАТЬ ИЗ - PullRequest
11 голосов
/ 13 апреля 2009

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

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

например, я выбираю из MV5.Posts и вставляю в MV6.Posts. После вставки я извлекаю идентификатор новой строки в MV6.Posts и обновляю его в старом поле MV5.Posts.MV6ID.

Есть ли способ сделать это ОБНОВЛЕНИЕ через INSERT INTO SELECT FROM, чтобы мне не приходилось обрабатывать каждую запись вручную? Я использую SQL Server 2005, версия для разработчиков.

Ответы [ 7 ]

10 голосов
/ 13 апреля 2009

Ключ с миграцией состоит в том, чтобы сделать несколько вещей: Во-первых, не делайте ничего без текущей резервной копии. Во-вторых, если ключи будут меняться, вам нужно как минимум временно временно сохранить старое и новое в новой структуре (постоянно, если поле ключа открыто для пользователей, поскольку они могут искать его, чтобы получить старые записи).

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

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

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

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

Update t2
set fkfield = newkey
from table2 t2
join table1 t1 on t1.oldkey = t2.fkfield

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

5 голосов
/ 13 апреля 2009

Вероятно, самым простым способом было бы добавить столбец MV6.Posts для oldId, а затем вставить все записи из старой таблицы в новую таблицу. Наконец, обновите соответствие старой таблицы для oldId в новой таблице следующим образом:

UPDATE mv5.posts
SET newid = n.id
FROM mv5.posts o, mv6.posts n 
WHERE o.id = n.oldid

Вы можете очистить и удалить столбец oldId впоследствии, если хотите.

3 голосов
/ 13 апреля 2009

Лучшее, что я могу сделать, - это предложение Предполагая, что у вас есть SQL 2005 или 2008.

USE AdventureWorks;
GO
DECLARE @MyTableVar table( ScrapReasonID smallint,
                           Name varchar(50),
                           ModifiedDate datetime);
INSERT Production.ScrapReason
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
        INTO @MyTableVar
VALUES (N'Operator error', GETDATE());

Для обновления исходной таблицы все равно потребуется второй проход; однако это может помочь упростить вашу логику. Вам нужно обновить исходную таблицу? Вы можете просто сохранить новые идентификаторы в третьей таблице перекрестных ссылок.

2 голосов
/ 13 апреля 2009

Есть ли способ сделать это ОБНОВЛЕНИЕ через INSERT INTO SELECT FROM, чтобы мне не приходилось обрабатывать каждую запись вручную?

Поскольку вы не хотите делать это вручную , но автоматически , создайте триггер на MV6.Posts, чтобы UPDATE происходил на MV5.Posts автоматически при вставке в MV6.Posts.

И ваш триггер может выглядеть примерно так:

create trigger trg_MV6Posts
on MV6.Posts
after insert
as
begin
    set identity_insert MV5.Posts on

    update  MV5.Posts
    set ID = I.ID
    from    inserted I

    set identity_insert MV5.Posts off
end
2 голосов
/ 13 апреля 2009

Хех. Я помню, как делал это во время миграции.

Помещение old_id в новую таблицу облегчает как обновление - вы можете просто сделать insert into newtable select ... from oldtable, так и последующее «сшивание» записей. В «стежке» вы либо обновите внешние ключи дочерних таблиц во вставке, выполнив выборку для нового родителя (insert into newchild select ... (select id from new_parent where old_id = oldchild.fk) as fk, ... from oldchild), либо вставите дочерние элементы и выполните отдельное обновление, чтобы исправить внешние ключи.

Делать это за одну вставку быстрее; выполняя это в отдельном шаге, вы понимаете, что ваши вставки не зависят от порядка и при необходимости могут быть повторены.

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

Действительно, если у вас правильно определены внешние ключи, вы можете использовать systables / information-schema для генерации операторов вставки.

1 голос
/ 13 апреля 2009

Сделать столбец в MV6.Post.OldMV5Id

сделать вставить в MV6.Post выберите .. из MV5.Post

затем обновите MV5.Post.MV6ID

1 голос
/ 13 апреля 2009

AFAIK, вы не можете обновить две разные таблицы одним оператором sql

Однако вы можете использовать триггеры для достижения того, что вы хотите сделать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...