Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Przypadki użycia instrukcji MERGE programu SQL Server:synchronizowanie tabel online i historii

WPROWADZENIE

Instrukcja SQL Server MERGE jest niezwykle przydatnym narzędziem do wykonywania operacji DML w oparciu o porównanie dwóch tabel lub dwóch zestawów danych. Użycie tej instrukcji jest w rzeczywistości jak wykonywanie wielu operacji w jednej instrukcji.

W tym artykule omówimy trzy przypadki użycia, które graniczą z zapewnieniem synchronizacji danych między tabelą online a tabelą historii.

Opiszmy ten scenariusz w kilku nakreślonych stwierdzeniach, które byłyby znane wielu administratorom baz danych lub programistom:

  1. Tabela źródłowa o nazwie Transfer na bieżąco rejestruje transakcje odbywające się w czasie rzeczywistym.
  2. Uzgodniony okres przechowywania dla tabeli Tran wynosi jeden miesiąc. Tran musi być czyszczony pod koniec każdego miesiąca.
  3. Codziennie dane Trana muszą być przesyłane do TranHistory podczas procesu „Koniec dnia”.
  4. TranHistory table to historyczna tabela agregująca dane transakcji z okresu jednego roku.
  5. Wszystkie wstawki i aktualizacje w Transu tabela musi odzwierciedlać w TranHistory stolik na koniec każdego dnia.

PRZYGOTOWANIE SCENARIUSZA

Opisany powyżej scenariusz sugeruje, że rekordy w tabeli Tran istnieją również w tabeli TranHistory, dopóki nie zostaną usunięte co miesiąc. Każdego dnia w tabeli Tran pojawi się kilka nowych rekordów, ale NIE w tabeli TranHistory. Musimy znaleźć sposób na wstawienie tych nowych wierszy.

Najpierw przygotujmy odpowiednie tabele (patrz Listing 1 i 2).

-- Listing 1: Create Tran Table
USE AU
GO
CREATE TABLE [Tran] (
  responseId int NOT NULL ,
  senderId varchar(15) ,
  msisdn varchar(15) ,
  [message] varbinary ,
  status smallint ,
  application varchar ,
  receivedTime timestamp NULL ,
  processedTime datetime2 NULL ,
  flag smallint ,
  requestDelivery smallint ,
  delivered smallint ,
  account varchar(20) ,
  srcTon smallint ,
  srcNpi smallint ,
  destTon smallint ,
  destNpi smallint ,
  errorCode smallint ,
  messageId varchar ,
  sequenceNo int ,
  retries smallint ,
  messagePriority int ,
  userId varchar(20) ,
  bulkId varchar(20) 
)
-- Listing 2: Create TranHistory Table
USE AU
GO
CREATE TABLE [TranHistory] (
  responseId int NOT NULL ,
  senderId varchar(15) ,
  msisdn varchar(15) ,
  [message] varchar(160) ,
  status smallint ,
  application varchar ,
  receivedTime datetime2 NULL ,
  processedTime datetime2 NULL ,
  flag smallint ,
  requestDelivery smallint ,
  delivered smallint ,
  account varchar(20) ,
  srcTon smallint ,
  srcNpi smallint ,
  destTon smallint ,
  destNpi smallint ,
  errorCode smallint ,
  messageId varchar ,
  sequenceNo int ,
  retries smallint ,
  messagePriority int ,
  userId varchar(20) ,
  bulkId varchar(20) ,
  archivedTime datetime2 NOT NULL ,
)

GDY NIE DOPASOWANO, WSTAWIĆ

Korzystając z kodu z Listingu 3, wstawiamy kilka wierszy w tabeli Tran, aby rozpocząć. Następnie przechodzimy do użycia instrukcji MERGE, aby przenieść dane do tabeli TranHistory.

-- Listing 3: Insert Initial Set of Rows in Tran Table
USE [AU]
GO

INSERT INTO [dbo].[Tran]
     VALUES
           (8000,'0233456789','Wishing you a Happy New Year',1,'K','20201110 15:00:00','20201110 15:10:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(7777,'0233456789','The blessing of the Lord be with you',1,'K','20201110 08:00:00','20201110 08:10:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(7005,'0234876789','Happy Birthday to you',1,'K','20201110 09:00:00','20201110 09:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(9002,'0233456789','Merry Christmas',1,'K','20201110 07:00:00','20201110 07:15:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(6789,'0233467889','Buy our brand new cars for less than $8000',1,'K','20201110 14:00:00','20201110 14:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(7685,'0244556789','Happy New Month. God bless and increase you',1,'K','20201110 17:00:00','20201110 17:08:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(4983,'0229856789','Help is coming your way today!',1,'K','20201110 19:00:00','20201110 19:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(6879,'0239986789','Call us for your next relocation project',1,'K','20201110 19:15:00','20201110 19:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(4567,'0233456789','Hard Work Always Pays',1,'K','20201110 22:05:00','20201110 22:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(8890,'0244656733','Don''t wait to buy land, buy land and wait',1,'K','20201110 15:05:00','20201110 15:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(6789,'0233466734','We are relocating. Call us on 077788997',1,'K','20201110 18:02:00','20201110 18:17:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(9899,'0233456556','Watch out for our latest movie',1,'K','20201110 06:00:00','20201110 06:02:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(6789,'0233456338','We are here to make you happy',1,'K','20201110 12:16:00','20201110 12:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
GO

Moglibyśmy to zrobić w znacznie prostszy sposób, ale chcemy pokazać składnię instrukcji MERGE (patrz Listing 4):

-- Listing 4: Merge Records in Tran Table to TranHistory Table
MERGE INTO [TranHistory] a USING [Tran] b
ON a.responseId=b.responseID
WHEN NOT MATCHED BY TARGET THEN INSERT
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],[archivedTime])
 VALUES 
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],getdate());
GO

Oświadczenie MERGE mówi:

  1. Weź zawartość tabeli [Tran] i porównaj ją z tabelą [TranHistory] na podstawie responseId kolumna.
  2. Wstaw te wiersze, które znajdziesz w tabeli źródłowej, ale których nie znajdziesz w tabeli docelowej (TranHistory).

W obecnej sytuacji Tran i TranHistory są na os. Załóżmy jednak, że następnego dnia w Tabeli Trans zostaną wprowadzone nowe wiersze. Musimy również przesunąć je do tabeli TransHistory, zachowując rekordy w tabeli Tran do końca miesiąca.

Ponownie używamy skryptu z listingu 4. Tym razem dodajemy klauzulę OUTPUT, aby poinformować, co zostało wprowadzone (patrz Listing 5):

-- Listing 5: Merge Records in Tran Table to TranHistory Table (Add OUTPUT Clause)
USE AU
GO

MERGE INTO [TranHistory] a USING [Tran] b
ON a.responseId=b.responseID
WHEN NOT MATCHED BY TARGET THEN INSERT
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],[archivedTime])
 VALUES 
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],getdate())
OUTPUT deleted.*, $action, inserted.*;
GO

Możemy powtórzyć ten proces po wprowadzeniu dodatkowych wierszy do tabeli Tran (Listing 6 i 7) i uzyskamy podobne zachowanie:

-- Listing 6: Insert Six New Rows in Tran Table
USE [AU]
GO

INSERT INTO [dbo].[Tran]
     VALUES
			(6879,'0239986789','Call us for your next relocation project',1,'K','20201110 19:15:00','20201110 19:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(4567,'0233456789','Hard Work Always Pays',1,'K','20201110 22:05:00','20201110 22:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(8890,'0244656733','Don''t wait to buy land, buy land and wait',1,'K','20201110 15:05:00','20201110 15:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(6789,'0233466734','We are relocating. Call us on 077788997',1,'K','20201110 18:02:00','20201110 18:17:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(9899,'0233456556','Watch out for our latest movie',1,'K','20201110 06:00:00','20201110 06:02:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(6789,'0233456338','We are here to make you happy',1,'K','20201110 12:16:00','20201110 12:20:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
GO
-- Listing 7: Insert Additional Three Rows in Tran Table
USE [AU]
GO

INSERT INTO [dbo].[Tran]
     VALUES
	(7789,'0233456433','Are you ready for your next level?',1,'K','20201110 14:35:00','20201110 14:40:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(8000,'0233457759','Hutchies Honey, another level of taste',1,'K','20201110 08:00:00','20201110 08:08:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(7777,'0233458909','Make sure you vote tomorrow',1,'K','20201110 09:45:00','20201110 09:50:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
			,(9890,'0233459994','Wishing you a Merry Christmas',1,'K','20201110 10:00:00','20201110 10:05:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
GO

PO DOPASOWANIU, AKTUALIZUJ

Innym przypadkiem jest aktualizacja tabeli na żywo (Tran), gdy chcemy zsynchronizować takie aktualizacje z tabelą TranHistory. Scenariusz ten tworzymy, aktualizując wiersze w tabeli Tran za pomocą skryptu z Listingu 8.

-- Listing 8: Update and Insert Rows in Tran Table
USE AU
GO

UPDATE [dbo].[Tran] SET account='JUNIPER' 
WHERE account='KAIROS';
GO

INSERT INTO [dbo].[Tran]
     VALUES
	(5578,'0233566933','Newest on the Block!',1,'K','20201110 14:35:00','20201110 14:40:00',1,1,1,'KAIROS',1,2,3,4,1,1,9789,2,1,'ROUTEMOBILE','9988776')
GO

Rysunek 6 pokazuje, że wiersze w tabeli docelowej są aktualizowane. Ten szczegół uzyskujemy za pomocą klauzuli OUTPUT.

Musimy użyć klauzuli wyróżnionej na Listingu 9. Wyciąg MERGE identyfikuje wiersze, które spełniają warunek JOIN i aktualizuje dane w określonej kolumnie (konto ). W ten sposób możemy zaktualizować wiele wierszy.

-- Listing 9: Sync Data in TranHistory by Updating Rows
USE AU
GO

MERGE INTO [TranHistory] a USING [Tran] b
ON a.responseId=b.responseID
WHEN MATCHED THEN UPDATE
SET a.account=b.account
WHEN NOT MATCHED BY TARGET THEN INSERT
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],[archivedTime])
 VALUES 
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],getdate())
OUTPUT deleted.*, $action, inserted.*;
GO

GDY NIE DOPASOWANO WEDŁUG ŹRÓDŁA, USUŃ

Jeszcze jeden scenariusz obejmuje usuwanie wierszy z tabeli źródłowej (Listing 10). Kiedy tak się dzieje, musimy zidentyfikować wiersze, które już nie istnieją w tabeli źródłowej i usunąć je z tabeli docelowej.

Osiągamy to za pomocą klauzuli wyróżnionej na Listingu 10. Ponownie, rysunki 7 i 8 pokazują wiersze, na które wpływa instrukcja MERGE.

-- Listing 10: Update and Insert Rows in Tran Table
USE AU
GO

DELETE FROM [dbo].[Tran] 
WHERE account='JUNIPER';
GO
-- Listing 11: Syncing Tables After Deleting from Tran Table
USE AU
GO

MERGE INTO [TranHistory] a USING [Tran] b
ON a.responseId=b.responseID
WHEN NOT MATCHED BY SOURCE THEN DELETE
WHEN MATCHED THEN UPDATE
SET a.account=b.account
WHEN NOT MATCHED BY TARGET THEN INSERT
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],[archivedTime])
 VALUES 
([responseId],[senderId],[msisdn],[message],[status],[application],[receivedTime],[processedTime],[flag],[requestDelivery],[delivered],[account],[srcTon],[srcNpi],[destTon],[destNpi],[errorCode],[messageId],[sequenceNo],[retries],[messagePriority],[userId],[bulkId],getdate())
OUTPUT deleted.*, $action, inserted.*;
GO

Rysunek 7 pokazuje wiersze, które zostały usunięte, a Rysunek 8 pokazuje te, które zostały zaktualizowane. To jest moc oświadczenia MERGE. Możemy wykonać operacje usuwania, wstawiania i aktualizowania w jednym oświadczeniu.

WNIOSEK

W tym artykule omówiono użycie instrukcji MERGE do synchronizowania danych między tabelą online a tabelą historii przy zachowaniu pożądanego przechowywania wymaganego w obu tabelach.

Istnieje wiele innych przypadków użycia instrukcji MERGE programu SQL Server, które nie zostały omówione w tym artykule, ale zostały one zbadane w dokumentacji firmy Microsoft. Dane źródłowe określone w klauzuli USING nie ograniczają się do tabel. Zestawy wyników z jawnych instrukcji SELECT mogą być danymi źródłowymi. Typowe wyrażenia tabelowe mogą również być danymi źródłowymi.

REFERENCJE

MERGE w Transact-SQL


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Entity Framework Code First z synonimami SQL Server

  2. Zaktualizować tabelę za pomocą JOIN w programie SQL Server?

  3. Skalarne wstawianie UDF w SQL Server 2019

  4. Zamiana NULL na 0 w zapytaniu do serwera SQL

  5. Klucze podstawowe w SQL Server