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

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

ОБНОВЛЕНИЕ: дополнительная информация: в целевой таблице уже есть данные.


person Daniel    schedule 19.10.2010    source источник


Ответы (3)


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

SET IDENTITY_INSERT ON для вашей целевой таблицы.

Вставьте в целевую таблицу исходные таблицы, присоединенные к таблице сопоставления, затем SET IDENTITY_INSERT OFF.

person Jeff Ogata    schedule 19.10.2010
comment
при создании удостоверения в таблице сопоставления задайте начальное значение, чтобы оно не конфликтовало с существующими данными. - person Jeff Ogata; 20.10.2010
comment
В этой статье MSDN говорится: Be cautious about using IDENT_CURRENT to predict the next generated identity value. The actual generated value may be different from IDENT_CURRENT plus IDENT_INCR because of insertions performed by other sessions. Есть ли способ надежно избежать конфликтов значения личности? - person Daniel; 20.10.2010
comment
Это кажется немного уродливым, но, возможно, это лучшее, что можно сделать. Я действительно хотел бы, чтобы это было возможно с помощью предложения OUTPUT. - person Daniel; 20.10.2010

Я создал таблицу сопоставления на основе предложения OUTPUT оператора MERGE. IDENTITY_INSERT не требуется.

В приведенном ниже примере есть RecordImportQueue и RecordDataImportQueue, а RecordDataImportQueue.RecordID — это FK для RecordImportQueue.RecordID. Данные в этих промежуточных таблицах должны быть перемещены в Record и RecordData, а FK должен быть сохранен.

RecordImportQueue to Record выполняется с помощью оператора MERGE, создавая таблицу сопоставления из своего OUTPUT, а RecordDataImportQueue переходит к RecordData с помощью INSERT из SELECT исходной таблицы, присоединенной к таблице сопоставления.

DECLARE @MappingTable table ([NewRecordID] [bigint],[OldRecordID] [bigint])

MERGE [dbo].[Record] AS target
USING (SELECT [InstanceID]
            ,RecordID AS RecordID_Original
            ,[Status]
        FROM [RecordImportQueue]
        ) AS source
ON (target.RecordID = NULL) -- can never match as RecordID is IDENTITY NOT NULL.
WHEN NOT MATCHED THEN
    INSERT ([InstanceID],[Status])
    VALUES (source.[InstanceID],source.[Status])
    OUTPUT inserted.RecordID, source.RecordID_Original INTO @MappingTable;

После этого вы можете вставить записи в таблицу ссылок следующим образом:

INSERT INTO [dbo].[RecordData]
    ([InstanceID]
    ,[RecordID]
    ,[Status])
SELECT [InstanceID]
    ,mt.NewRecordID -- the new RecordID from the mappingtable
    ,[Status]
FROM [dbo].[RecordDataImportQueue] AS rdiq
JOIN @MappingTable AS mt
ON rdiq.RecordID = mt.OldRecordID

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

person Bert Van Landeghem    schedule 25.03.2013

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

person Joe Stefanelli    schedule 19.10.2010
comment
Это предполагает, что я могу изменить схему целевой таблицы, что я и могу, но мне любопытно, как это можно решить, если это невозможно. - person Daniel; 20.10.2010
comment
@Daniel: По сути, я бы использовал ту же технику, но вместо изменения целевой таблицы я бы создал временную таблицу, которая состояла бы из схемы целевой таблицы (включая столбец идентификаторов) плюс дополнительный старый столбец идентификатора. Вставьте во временную таблицу, затем используйте SET IDENTITY_INSERT NewTable ON и вставьте из временной таблицы в новую таблицу. Не забудьте SET IDENTITY_INSERT NewTable OFF, когда закончите. - person Joe Stefanelli; 20.10.2010
comment
Не могли бы вы столкнуться с конфликтующими значениями идентификаторов при вставке в целевую таблицу? - person Daniel; 20.10.2010
comment
Только что заметил, что мой предыдущий комментарий в основном такой же, как ответ по течению - person Joe Stefanelli; 20.10.2010
comment
@Daniel: как упоминалось в adrift answer, установите начальное семя идентификатора во временной таблице достаточно высоким, чтобы избежать существующих значений в целевой таблице, и все будет в порядке. - person Joe Stefanelli; 20.10.2010