Insertion de lignes multiples :
L'objectif est de créer plusieurs lignes dans la base sur un seul ordre INSERT .
Tout d'abord, rappelons les INSERT classiques ....
Soit une simple table :
create
table [dbo].[Matable](
[MaCle] [int] NOT
null,
[Valeur] [varchar](50)
null
)
ON [primary]
On insère une ligne avec les colonnes dans l'ordre supposé du dictionnaire :
insert
into dbo.Matable
values
(1,'Dominique')
C'est déconseillé car , que se passe-t-il si vous changez la structure de la table ??
Exemple amusant :
drop
table [dbo].[Matable]
go
create
table [dbo].[Matable](
[MaCle] [int] NOT
null,
[UneAutreValeur] [varchar](50)
null
[Valeur] [varchar](50)
null
)
ON [primary]
puis :
insert
into dbo.Matable
values
(1,'Dominique')
Bien sûr, la colonne cible n'est plus celle que l'on pense !
Il faut utiliser :
insert
into dbo.Matable (MaCle,Valeur)
values
(2,'David')
Et maintenant, la nouveauté SQL2008 :
insert
into dbo.Matable (MaCle,Valeur)
values
(3,'David'),(4,'Maelle')
On insère dans un seul ordre DML n lignes.
cela peut être sympathique pour des scripts de chargement de données de réference....
L'instruction MERGE :
Vous avez sans doute tous eu, comme moi, à résoudre le problème suivant :
j'ai des données dans une table de référence, mais la source de mise à jour de ces données est multiple,je vais donc avoir à fusionner (MERGE) deux tables pour en obtenir une seul à jour.
Ceci est très fréquent avec des progiciels dont la propagation des mises à jour n'est pas temps réel.
Voyons la syntaxe de cette fusion :
MERGE [ into ] tableCible [ [ AS ] AliasDetable ]
[ WITH USING tableSource
ON ConditionDeRecherche
[ WHEN MATCHED THEN InstructionsSiCorrespondance ]
[ WHEN NOT MATCHED THEN InstructionsSiNonCorrespondance ]
Et maintenant des données de test pour voir le tout en fonctionnement :
create
table Source
(NoPersonnel int
not
null,
Nom varchar(50),
constraint pk_Source primary
key
clustered
(NoPersonnel))
insert
into Source values
(1,'Pierre'),(2,'Paula épouse Durand')
select
*
from Source
NoPersonnel Nom
----------- --------------------------------------------------
1 Pierre
2 Paula épouse Durand
(2 row(s) affected)
create
table Cible
(NoPersonnel int
not
null,
Nom varchar(50),
constraint pk_Cible primary
key
clustered
(NoPersonnel))
insert
into Cible values
(2,'Paula')
select
*
from Cible
NoPersonnel Nom
----------- --------------------------------------------------
2 Paula
(1 row(s) affected)
L'objectif étant bien sûr, que notre 'épouse Durand' écrase la donée cible, et que la ligne manquante soit insérée.
Ecrivons donc l'ordre MERGE :
MERGE
into Cible
using [Source]
ON Cible.NoPersonnel = Source.NoPersonnel
WHEN MATCHED THEN
update
set Nom = Source.nom
WHEN
NOT MATCHED THEN
insert
(NoPersonnel,Nom)
values
(Source.NoPersonnel,Source.Nom);
select
*
from Cible
NoPersonnel Nom
----------- --------------------------------------------------
1 Pierre
2 Paula épouse Durand
(2 row(s) affected)
On se retrouve bien avec les données à niveau après fusion.
Attention, comme très souvent dans les nouvelles évolutions de TSQL, le ; est obligatoire en fin d'instruction :
MERGE
into Cible
using [Source]
ON Cible.NoPersonnel = Source.NoPersonnel
WHEN MATCHED THEN
update
set Nom = Source.nom
WHEN
NOT MATCHED THEN
insert
(NoPersonnel,Nom)
values
(Source.NoPersonnel,Source.Nom)
Msg 10713, Level 15, State 1, Line 7
A MERGE statement must be terminated by a semi-colon (;).
Ayant eu à écrire moi-même un interpréteur de langage il y a quelques années, je pense que la raison d'être de ce ; est lié au caractère non déterministe de certaines formulations :
Un langage informatique DOIT être déterministe, c'est à dire qu'il ne peut y avoir qu'une interprétation possible d'une phrase donnée (ce qui n'est pas le cas de notre bon vieux Français, et encore moins de l'Anglais, Par ex : le météorologue voyait venir la dépression...)
Conclusion :
Voilà un MERGE que l'on attendait depuis longtemps et qui devrait économiser bien des efforts aux développeurs (en tout cas à ceux qui veulent encore se servir des bases de données)...