Instrukcja MERGE to sposób, aby jednym zapytaniem wykonać 3 operacje naraz: INSERT, UPDATE, DELETE.
Najczęściej używa się jej do synchronizacji danych między dwiema
tabelami:
- źródłową (np. dane z importu)
- docelową (np.
tabela produkcyjna)
1. Przykład z życia – aktualizacja klientów po imporcie
Załóżmy, że codziennie ładujesz dane klientów do
tabeli tymczasowej #Klienci_Import, a Twoja tabela docelowa to Klienci. Chcesz:
- zaktualizować
dane, które się zmieniły,
- dodać
nowych klientów,
- usunąć
tych, których już nie ma w CRM.
Kod SQL:
--dane
drop table if exists Klienci;
drop table if exists #Klienci_Import;
create table Klienci (KlientID int IDENTITY(1,1) primary key not null, Imie varchar(20),Nazwisko varchar(20));
create table #Klienci_Import (KlientID int IDENTITY(1,1) primary key not null, Imie varchar(20),Nazwisko varchar(20));
--tabela bazowa i co sie bedzie dziac
insert into Klienci (Imie,Nazwisko) select 'Jarek','Kowalski' --bez zmian
insert into Klienci (Imie,Nazwisko) select 'Mirek','Maliniak' --to update
insert into Klienci (Imie,Nazwisko) select 'Wacek','Placek' --to del
--aktualna lista
insert into #Klienci_Import (Imie,Nazwisko) select 'Jarek','Kowalski'
insert into #Klienci_Import (Imie,Nazwisko) select 'Mirosław','Malinowski'
--merge na tabeli #Klienci na podstawie #Klienci_Import
MERGE Klienci WITH (HOLDLOCK) AS Target
USING #Klienci_Import AS Source
ON Target.KlientID = Source.KlientID
--upd
WHEN MATCHED AND (Target.Imie <> Source.Imie OR Target.Nazwisko <> Source.Nazwisko)
THEN UPDATE SET Target.Imie = Source.Imie, Target.Nazwisko = Source.Nazwisko
--ins
WHEN NOT MATCHED BY TARGET THEN
INSERT (Imie, Nazwisko)
VALUES (Source.Imie, Source.Nazwisko)
--del
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
--check
select * from Klienci
Results:
KlientID Imie Nazwisko
----------- -------------------- --------------------
1 Jarek Kowalski
2 Mirosław Malinowski
2. Co tu się dzieje
- Klienci_Import – to źródło danych (np. nowy import z CRM).
- Klienci – to tabela docelowa z aktualnymi danymi.
- SQL Server porównuje rekordy po KlientID:
- jeśli rekord istnieje w obu tabelach, ale dane się różnią → robi UPDATE,
- jeśli rekord istnieje tylko w źródle → robi INSERT,
- jeśli rekord istnieje tylko w docelowej → robi DELETE.
3. Dlaczego WITH (HOLDLOCK) jest ważne
HOLDLOCK mówi SQL Serverowi, żeby potraktował całą tabelę
docelową jakby działała w trybie SERIALIZABLE – czyli żadna inna
transakcja nie może jej zmienić w trakcie wykonywania MERGE.
Dzięki temu masz gwarancję, że:
- dane nie zostaną przypadkowo nadpisane przez równoległe procesy,
- MERGE wykona się w sposób spójny i przewidywalny.
Bez tej blokady, przy dużym ruchu w bazie, możesz złapać tzw. race condition, czyli błędną aktualizację spowodowaną zmianą danych w trakcie operacji.
4. Po co ten warunek w WHEN MATCHED
Domyślnie MERGE wykona UPDATE nawet wtedy, gdy
wartości kolumn są identyczne.
To powoduje zbędne zapisy do loga, blokady, a czasem uruchamianie triggerów.
Dlatego warto dopisać warunek:
WHEN MATCHED AND (Target.Kolumna <> Source.Kolumna)
Dzięki temu aktualizujesz tylko faktyczne zmiany.
5. Podsumowanie
MERGE to potężne narzędzie, które pozwala w prosty sposób
utrzymać dane zsynchronizowane między dwiema tabelami.
Z HOLDLOCK masz bezpieczeństwo, a z warunkiem w WHEN MATCHED – wydajność i
czystość loga transakcyjnego.
To rozwiązanie sprawdza się idealnie przy:
- codziennych importach danych,
- procesach ETL,
- integracjach z systemami zewnętrznymi.
Jedno polecenie, pełna kontrola nad danymi.