У меня есть веб-приложение, которое использует довольно большую таблицу (миллионы строк, около 30 столбцов). Давайте назовем это TableA. Среди 30 столбцов эта таблица имеет первичный ключ с именем «id», а другой столбец с именем «campaignID».
В рамках приложения пользователи могут загружать новые наборы данных, относящихся к новым «кампаниям».
Эти наборы данных имеют ту же структуру, что и ТаблицаA, но обычно только около 10 000–20 000 строк.
Каждая строка в новом наборе данных будет иметь уникальный идентификатор, но все они будут иметь один и тот же идентификатор кампании. Другими словами, пользователь загружает полные данные для новой «кампании», поэтому все 10000 строк имеют одинаковый «campaignID».
Обычно пользователи загружают данные для НОВОЙ кампании, поэтому в Таблице А нет строк с одинаковым идентификатором кампании. Поскольку «идентификатор» уникален для каждой кампании, идентификатор каждой строки новых данных будет уникальным в таблице А.
Однако в редком случае, когда пользователь пытается загрузить новый набор строк для «кампании», которая уже находится в базе данных, требовалось сначала удалить все старые строки для этой кампании из TableA, а затем вставить новые строки из нового набора данных.
Итак, моя хранимая процедура была простой:
- BULK INSERT новые данные во временную таблицу (#tableB)
- Удалить все существующие строки в Таблице A с тем же идентификатором кампании
- INSERT INTO Таблица A ([столбцы]) SELECT [столбцы] из # TableB
- Drop # TableB
Это сработало просто отлично.
Но новое требование - предоставить пользователям 3 варианта при загрузке новых данных для обработки «дубликатов» - случаев, когда пользователь загружает данные для кампании, которая уже находится в Таблице A.
- Удалите ВСЕ данные в Таблице A с тем же идентификатором кампании, затем вставьте все новые данные из таблицы #TableB. (Это старое поведение. С этой опцией они никогда не будут дубликатами.)
- Если строка в #TableB имеет тот же идентификатор, что и строка в TableA, то обновите эту строку в TableA строкой из #TableB (фактически, это «замена» старых данных новыми данными)
- Если строка в #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