«Объединение» двух таблиц в T-SQL - замена или сохранение повторяющихся идентификаторов - PullRequest
3 голосов
/ 28 апреля 2009

У меня есть веб-приложение, которое использует довольно большую таблицу (миллионы строк, около 30 столбцов). Давайте назовем это TableA. Среди 30 столбцов эта таблица имеет первичный ключ с именем «id», а другой столбец с именем «campaignID».

В рамках приложения пользователи могут загружать новые наборы данных, относящихся к новым «кампаниям».

Эти наборы данных имеют ту же структуру, что и ТаблицаA, но обычно только около 10 000–20 000 строк.

Каждая строка в новом наборе данных будет иметь уникальный идентификатор, но все они будут иметь один и тот же идентификатор кампании. Другими словами, пользователь загружает полные данные для новой «кампании», поэтому все 10000 строк имеют одинаковый «campaignID».

Обычно пользователи загружают данные для НОВОЙ кампании, поэтому в Таблице А нет строк с одинаковым идентификатором кампании. Поскольку «идентификатор» уникален для каждой кампании, идентификатор каждой строки новых данных будет уникальным в таблице А.

Однако в редком случае, когда пользователь пытается загрузить новый набор строк для «кампании», которая уже находится в базе данных, требовалось сначала удалить все старые строки для этой кампании из TableA, а затем вставить новые строки из нового набора данных.

Итак, моя хранимая процедура была простой:

  1. BULK INSERT новые данные во временную таблицу (#tableB)
  2. Удалить все существующие строки в Таблице A с тем же идентификатором кампании
  3. INSERT INTO Таблица A ([столбцы]) SELECT [столбцы] из # TableB
  4. Drop # TableB

Это сработало просто отлично.

Но новое требование - предоставить пользователям 3 варианта при загрузке новых данных для обработки «дубликатов» - случаев, когда пользователь загружает данные для кампании, которая уже находится в Таблице A.

  1. Удалите ВСЕ данные в Таблице A с тем же идентификатором кампании, затем вставьте все новые данные из таблицы #TableB. (Это старое поведение. С этой опцией они никогда не будут дубликатами.)
  2. Если строка в #TableB имеет тот же идентификатор, что и строка в TableA, то обновите эту строку в TableA строкой из #TableB (фактически, это «замена» старых данных новыми данными)
  3. Если строка в #TableB имеет тот же идентификатор, что и строка в TableA, игнорируйте эту строку в #TableB (по сути, это сохранение исходных данных и игнорирование новых данных).

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

В аналогичном приложении, которое я работал с MySQL, я использовал функцию «LOAD DATA INFILE» с опцией «REPLACE» или «IGNORE». Но я не знаю, как это сделать с SQL Server / T-SQL.

Любое решение должно быть достаточно эффективным, чтобы справиться с тем фактом, что TableA имеет миллионы строк, а #TableB (новый набор данных) может иметь строки 10k-20k.

Я гуглил что-то вроде команды «Объединить» (что, похоже, поддерживается в SQL Server 2008), но у меня есть доступ только к SQL Server 2005.

В грубом псевдокоде мне нужно что-то вроде этого:

Если пользователь выбирает вариант 1: [У меня все готово - у меня это работает]

Если пользователь выбирает вариант 2 (заменить):

merge into TableA as Target
using #TableB as Source
    on TableA.id=#TableB.id
when matched then 
    update row in TableA with row from #TableB
when not matched then
    insert row from #TableB into TableA

Если пользователь выбирает вариант 3 (сохранить):

merge into TableA as Target
using #TableB as Source
    on TableA.id=#TableB.id
when matched then 
    do nothing
when not matched then
    insert row from #TableB into TableA

Ответы [ 2 ]

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

Как насчет этого?

вариант 2:

begin tran;
delete from tablea where exists (select 1 from tableb where tablea.id=tableb.id);
insert into tablea select * from tableb;
commit tran;

вариант 3:

begin tran;
delete from tableb where exists (select 1 from tablea where tablea.id=tableb.id);
insert into tablea select * from tableb;
commit tran;

Что касается производительности, то пока поля (ы) id в таблице (большой таблице) проиндексированы, все будет в порядке.

0 голосов
/ 02 января 2012

Почему вы используете Upserts, когда он утверждает, что хотел MERGE? MAREG в SQL 2008 быстрее и эффективнее.

Я бы позволил слиянию обработать различия.

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