TSQL: ОБНОВЛЕНИЕ с INSERT INTO SELECT FROM

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

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

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

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


person tsilb    schedule 12.04.2009    source источник


Ответы (7)


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

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

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

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

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

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

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

person HLGEM    schedule 13.04.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 после этого, если хотите.

person Joel    schedule 12.04.2009
comment
Я действительно думаю, что оставлять oldId в новой таблице предпочтительнее, чем иметь newId в старой таблице, что делает это еще проще. - person ninesided; 13.04.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());

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

person JoshBerke    schedule 12.04.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 для генерации ваших операторов вставки.

person tpdi    schedule 12.04.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
person dance2die    schedule 12.04.2009

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

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

person Brann    schedule 12.04.2009

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

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

затем сделайте обновление MV5.Post.MV6ID

person Christian Johansson    schedule 12.04.2009