Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Cas d'utilisation de l'instruction SQL Server MERGE :synchronisation des tables en ligne et d'historique

PRESENTATION

L'instruction SQL Server MERGE est un outil extrêmement utile pour effectuer des opérations DML basées sur la comparaison de deux tables ou de deux ensembles de données. L'utilisation de cette instruction revient en fait à effectuer plusieurs opérations dans une seule instruction.

Cet article explore trois cas d'utilisation qui limitent la synchronisation des données entre une table en ligne et une table d'historique.

Décrivons le scénario en quelques déclarations décrites qui seraient familières à de nombreux administrateurs de bases de données ou développeurs :

  1. La table source appelée Tran capture les transactions qui se produisent en temps réel sur une base continue.
  2. La période de conservation convenue pour la table Tran est d'un mois. Tran doit être purgé à la fin de chaque mois.
  3. Chaque jour, les données de Tran doivent être poussées vers TranHistory pendant le processus de "fin de journée".
  4. La TranHistory table est un tableau historique regroupant les données de transaction sur une année.
  5. Tous les encarts et mises à jour sur Tran la table doit refléter dans TranHistory tableau à la fin de chaque journée.

PRÉPARER LE SCÉNARIO

Le scénario décrit ci-dessus implique que les enregistrements de la table Tran existent également dans la table TranHistory jusqu'à ce qu'ils soient purgés mensuellement. Chaque jour, il y aura quelques nouveaux enregistrements dans la table Tran mais PAS dans la table TranHistory. Nous devons trouver un moyen d'insérer ces nouvelles lignes.

Préparons d'abord les tableaux en question (Voir Listing 1 et 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 ,
)

LORSQU'IL N'Y A PAS CORRESPONDANCE, ALORS INSÉRER

En utilisant le code du Listing 3, nous insérons quelques lignes dans la table Tran pour commencer. Ensuite, nous procédons à l'utilisation d'une instruction MERGE pour déplacer les données vers la table 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

Nous aurions pu le faire de manière beaucoup plus simple, mais nous voulons montrer la syntaxe de l'instruction MERGE (voir 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

L'instruction MERGE indique :

  1. Prenez le contenu de la table [Tran] et comparez-le avec la table [TranHistory] basée sur le responseId colonne.
  2. Insérez les lignes que vous trouvez dans la table source mais que vous ne trouvez pas dans la table cible (TranHistory).

En l'état, Tran et TranHistory sont à par. Mais supposons que le jour suivant, de nouvelles lignes soient introduites dans la table Trans. Nous devons également les pousser vers la table TransHistory tout en conservant les enregistrements dans la table Tran jusqu'à la fin du mois.

Nous utilisons à nouveau le script du listing 4. Cette fois, nous ajoutons une clause OUTPUT pour indiquer ce qui a été introduit (voir 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

Nous pouvons répéter ce processus après avoir introduit des lignes supplémentaires dans la table Tran (Listes 6 et 7), et nous obtenons un comportement similaire :

-- 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

LORSQUE CORRESPOND, PUIS METTRE À JOUR

Un autre cas est une mise à jour de la table en direct (Tran) lorsque nous voulons synchroniser ces mises à jour avec la table TranHistory. Nous créons ce scénario en mettant à jour les lignes de la table Tran à l'aide du script du Listing 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

La figure 6 montre que les lignes sont mises à jour dans la table de destination. Nous obtenons ce détail en utilisant la clause OUTPUT.

Nous devons utiliser la clause mise en évidence dans le Listing 9. L'instruction MERGE a identifié les lignes qui correspondent à la condition JOIN et met à jour les données dans la colonne spécifiée (compte ). Nous pouvons mettre à jour plusieurs lignes avec cette approche.

-- 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

LORSQUE LA SOURCE NE CORRESPOND PAS, PUIS SUPPRIMER

Un autre scénario implique la suppression de lignes de la table source (Liste 10). Lorsque cela se produit, nous devons identifier les lignes qui n'existent plus dans la table source et les supprimer de la table de destination.

Pour ce faire, nous utilisons la clause mise en évidence dans le Listing 10. Encore une fois, les figures 7 et 8 montrent les lignes impactées par cette instruction 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

La figure 7 montre les lignes qui ont été supprimées et la figure 8 montre celles qui ont été mises à jour. C'est le pouvoir de l'instruction MERGE. Nous pouvons effectuer des opérations de suppression, d'insertion et de mise à jour en une seule déclaration.

CONCLUSION

Cet article a passé en revue l'utilisation de l'instruction MERGE pour synchroniser les données entre une table en ligne et une table d'historique tout en conservant la rétention souhaitée requise dans les deux tables.

Il existe de nombreux autres cas d'utilisation des instructions SQL Server MERGE non couverts dans cet article, mais ils sont explorés dans la documentation Microsoft. Les données source spécifiées dans la clause USING ne sont pas limitées aux tables. Les ensembles de résultats d'instructions SELECT explicites peuvent être des données source. Les expressions de table courantes peuvent également être des données source.

RÉFÉRENCES

FUSIONNER en Transact-SQL