Я пишу процесс импорта, который будет импортировать данные из одной (несколько устаревшей) базы данных в другую. Процесс импорта занимает одну плоскую таблицу с исходными данными. У меня есть это заполнение временной таблицы (#SourcePersonAccount
) в начале. Цель состоит в том, чтобы распределить эти данные в три таблицы назначения (dbo.Person
, dbo.Account
& dbo.PersonAccount
). Это выполняется в триггере для таблицы, использующей репликацию SQL Server, поэтому должен выполняться быстро.
#SourcePersonAccount([AccountNumber], [CompanyId], [TargetPersonId], [TargetAccountId]);
dbo.Person ([Id] pk identity(1,1), [CompanyId], ...);
dbo.Account ([Id] pk identity(1,1), [AccountNumber], ...);
dbo.PersonAccount ([Id], [PersonId] fk_Person_Id, [AccountId] fk_Account_Id);
В моем коде у меня есть TargetPersonId
, уже заполненный во временной таблице #SourcePersonAccount
. Осталось только: 1) вставить в dbo.Account
, 2) обновить #SourcePersonAccount
с добавленным значением dbo.Account.Id
, 3) вставить в dbo.PersonAccount
.
Одна из проблем заключается в том, что AccountNumber
и CompanyId
составляют составной первичный ключ исходной таблицы, поэтому они необходимы для правильного соединения с временной таблицей #SourcePersonAccount
.
Я видел потоки, в определенной степени решающие подобные проблемы здесь и здесь , которые не решили мою конкретную проблему, в основном из-за проблем с производительностью.
Как указано в в этом посте , предложение OUTPUT
не может выводить столбцы, которые не были включены во вставку, так что это не вариант здесь.
Одно решение, которое я видел, технически может дать желаемый результат (я не могу найти ссылку на то, где я нашел предложение) при использовании предложения OUTPUT
фактически добавляется и удаляется столбец в запросе.
DECLARE @PersonAccountTbl TABLE ([AccountId] INT, [AccountNumber] INT, [CompanyId] INT);
ALTER TABLE [dbo].[Account]
ADD [CompanyId] INT NULL;
INSERT INTO [dbo].[Account]
([AccountNumber], [CompanyId])
OUTPUT INSERTED.[Id], INSERTED.[AccountNumber], INSERTED.[CompanyId]
INTO @PersonAccountTbl
SELECT
[AccountNumber], [CompanyId]
FROM #SourcePersonAccount
WHERE
[TargetAccountId] IS NULL;
ALTER TABLE [dbo].[Account]
DROP COLUMN [CompanyId];
Это недопустимый вариант для моей ситуации.
Я пытался использовать MERGE
как и все темы, которые я нашел в этом выпускеМы рекомендуем использовать его. Мне не нравится MERGE
по по нескольким причинам . Я все равно попробовал;приведенный ниже код дает желаемый результат, но в конечном итоге он оказался слишком медленным для моих целей.
DECLARE @PersonAccountTbl TABLE ([AccountId] INT, [AccountNumber] INT, [CompanyId] INT);
MERGE INTO [dbo].[Account] a
USING #SourcePersonAccount spa
ON spa.[TargetAccountId] IS NULL
WHEN NOT MATCHED THEN
INSERT
([AccountNumber])
VALUES
(spa.[AccountNumber])
OUTPUT INSERTED.[Id], INSERTED.[AccountNumber], spa.[CompanyId]
INTO @PersonAccountTbl ([AccountId], [AccountNumber], [CompanyId]);
UPDATE spa
SET spa.[TargetAccountId] = pat.[AccountId]
FROM #SourcePersonAccount spa
JOIN @PersonAccountTbl pat
ON pat.[AccountNumber] = spa.[AccountNumber]
AND pat.[CompanyId] = spa.[CompanyId];
INSERT INTO [dbo].[PersonAccount]
([PersonId], [AccountId])
SELECT
spa.[TargetPersonId], spa.[TargetAccountId]
FROM #SourcePersonAccount spa
LEFT JOIN [dbo].[PersonAccount] pa
ON pa.[PersonId] = spa.[TargetPersonId]
AND pa.[AccountId] = spa.[TargetAccountId]
WHERE
pa.[Id] IS NULL;
Есть ли способ , отличный от MERGE
или добавление / удаление столбца длявыполнить это?