SQL Server: вставка записей в таблицу, если их нет
Быстрый ответ
Если требуется вставить данные в отсутствии дубликатов, воспользуйтесь следующим запросом:
INSERT INTO ВашаТаблица (Колонка1, Колонка2)
SELECT Значение1, Значение2
WHERE NOT EXISTS (
SELECT 1 FROM ВашаТаблица WHERE НекаяКолонка = НекоеЗначение
)
Замените идентификаторы колонок и соответствующие значения в вашей таблице. Данный запрос с использованием WHERE NOT EXISTS
проверяет избежание дублирования и сокращает код без потери функциональности.
Проблема гонок состояний
Будьте в курсе возможных гонок состояний. Они происходят, когда другая транзакция вставляет аналогичные данные между моментом проверки и выполнением INSERT
. Чтобы минимизировать этот риск, используйте уровни изоляции транзакций или блокировки таблиц:
BEGIN TRANSACTION;
IF NOT EXISTS (SELECT * FROM ВашаТаблица WHERE НекаяКолонка = НекоеЗначение)
BEGIN
INSERT INTO ВашаТаблица (Колонка1, Колонка2) VALUES (Значение1, Значение2);
END;
COMMIT TRANSACTION;
Использование MERGE для условной вставки
Для условной вставки рекомендуется использовать MERGE
:
MERGE INTO ВашаТаблица AS Цель
USING (VALUES (Значение1, Значение2)) AS Источник (Колонка1, Колонка2)
ON Цель.НекаяКолонка = Источник.НекаяКолонка
WHEN NOT MATCHED THEN
INSERT (Колонка1, Колонка2)
VALUES (Источник.Колонка1, Источник.Колонка2);
При применении MERGE
проявляйте осторожность, поскольку это может повлиять на производительность при интенсивной параллельной работе.
Борьба с дублированием данных при помощи подзапросов и соединений
Для сложных проверок на существование данных, воспользуйтесь подзапросом или LEFT JOIN:
INSERT INTO ВашаТаблица (Колонка1, Колонка2, ...)
SELECT temp.Колонка1, temp.Колонка2, ...
FROM (
SELECT Значение1 AS Колонка1, Значение2 AS Колонка2, ...
) AS temp
LEFT JOIN ВашаТаблица ON ВашаТаблица.НекаяКолонка = temp.Колонка1
WHERE ВашаТаблица.НекаяКолонка IS NULL;
Для опытных специалистов (работа с большими объёмами данных)
При работе с большими объёмами данных важно обратить особое внимание на производительность методов вставки и искать путей их оптимизации:
BEGIN TRANSACTION;
IF NOT EXISTS (SELECT * FROM ВашаТаблица WHERE НекаяКолонка = НекоеЗначение)
BEGIN
INSERT INTO ВашаТаблица (Колонка1, Колонка2) VALUES (Значение1, Значение2);
END;
COMMIT TRANSACTION;
Визуализация
Приведем аналогию. Вы ответственны за гардероб на съемочной площадке голливудского блокбастера и обязаны предоставить каждому костюму конкретный шкафчик:
Гардероб: [Костюм1, Костюм2, Костюм3, ...]
Функция INSERT if not exists
служит как распределитель шкафчиков для новых костюмов, при условии, что у них еще нет собственного места:
IF NOT EXISTS (SELECT * FROM Гардероб WHERE ID='Костюм4')
INSERT INTO Гардероб (ID, Шкафчик) VALUES ('Костюм4', '🎒');
В итоге получаем:
До: [Костюм1, Костюм2, Костюм3, ...]
После: [Костюм1, Костюм2, Костюм3, Костюм4(🎒), ...]
Адаптация к реальным ситуациям
В практической работе INSERT if not exists
может встраиваться в крупные операции, например в хранящиеся процедуры или в транзакции, включающие несколько таблиц:
CREATE PROCEDURE InsertIfNotExists
@Колонка1Значение Тип1,
@Колонка2Значение Тип2
AS
BEGIN
IF NOT EXISTS (SELECT 1 FROM ВашаТаблица WHERE Колонка1 = @Колонка1Значение)
BEGIN
INSERT INTO ВашаТаблица (Колонка1, Колонка2)
VALUES (@Колонка1Значение, @Колонка2Значение);
END;
END;
Настройка вашего инструмента при помощи EXCEPT
Если требуется оптимизация производительности, рассмотрите возможность использования EXCEPT
для исключения уже существующих записей в процессе вставки:
INSERT INTO ВашаТаблица (Колонка1, Колонка2)
SELECT Колонка1, Колонка2
FROM (
SELECT Значение1, Значение2
EXCEPT
SELECT Колонка1, Колонка2 FROM ВашаТаблица
) AS Данные