{"id":267,"date":"2011-04-09T00:00:35","date_gmt":"2011-04-09T00:00:35","guid":{"rendered":"http:\/\/www.sqlserver.fr\/blog\/?p=267"},"modified":"2026-05-02T14:31:22","modified_gmt":"2026-05-02T12:31:22","slug":"trigger-ensembliste","status":"publish","type":"post","link":"https:\/\/www.sqlserver.fr\/blog\/trigger-ensembliste\/","title":{"rendered":"Trigger Ensembliste"},"content":{"rendered":"<p>Suivant les exp\u00e9riences et sensibilit\u00e9s de chacun, les D\u00e9clencheurs (Triggers en anglais) sont accept\u00e9s et utilis\u00e9s par certains, ou fuis comme la peste par d\u2019autres.<br \/>\nOutre l\u2019architecture technique permettant parfois d\u2019exclure les codages sous forme de d\u00e9clencheurs, il est aussi indispensable de bien comprendre le principe de fonctionnement des d\u00e9clencheurs afin de ne pas laisser tra\u00eener des bugs qui seront tr\u00e8s difficiles \u00e0 corriger.<!--more--><\/p>\n<p>Nous ne nous int\u00e9resserons ici qu\u2019aux d\u00e9clencheurs de type DML (Data Modification Language), car c\u2019est ce type de d\u00e9clencheurs qui peut le plus souvent \u00eatre mal ma\u00eetris\u00e9 et au final devenir contre-productif.<\/p>\n<p>Premi\u00e8rement, qu\u2019est-ce qu\u2019un d\u00e9clencheur ? Et bien c\u2019est un bloc de code qui s\u2019ex\u00e9cute automatiquement, de mani\u00e8re totalement implicite, apr\u00e8s ou \u00e0 la place d\u2019une instruction de modification (INSERT, DELETE ou UPDATE) dans une table donn\u00e9e. Ce d\u00e9clencheur s\u2019ex\u00e9cutera automatiquement pour chaque instruction concern\u00e9e. Prenons par exemple le code suivant (je m\u2019appuierai ici sur les bases d\u2019exemple issues de <a href=\"https:\/\/github.com\/Microsoft\/sql-server-samples\/releases\/tag\/adventureworks\">http:\/\/msftdbprodsamples.codeplex.com\/<\/a>) :<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">CREATE TRIGGER Sales.trigCurrency\r\n   ON  Sales.Currency\r\n   AFTER INSERT\r\nAS\r\nBEGIN\r\n\tDECLARE @name nvarchar(50)\r\n\tSELECT @name = Name\r\n\tFROM inserted\r\n\tIF len(@name) &lt; 5\r\n\tBEGIN\r\n\t\tROLLBACK TRANSACTION\r\n\tEND\r\nEND<\/pre>\n<p>Ce d\u00e9clencheur s\u2019ex\u00e9cute automatiquement lors de chaque instruction INSERT sur la table Sales.Currency. On remarquera donc que si les \u00e9changes entre le client et le serveur SQL se fait sous forme CRUD (Create \/ Read \/ Update \/ Delete), avec des instructions unitaires, le co\u00fbt d\u2019ex\u00e9cution du d\u00e9clencheur peut \u00eatre non n\u00e9gligeable. Ainsi, si 20 instructions INSERT sont ex\u00e9cut\u00e9es pour d\u00e9finir 20 nouvelles devises, le d\u00e9clencheur sera ex\u00e9cut\u00e9 20 fois.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">set nocount on\r\ndeclare @compteur int=0\r\nwhile @compteur&lt;20\r\nbegin\r\n\tinsert into Sales.Currency (CurrencyCode,Name,ModifiedDate)\r\n\t\tselect N'X'+convert(nvarchar(2),@compteur),\r\n\t\t\t\tN'DEVISE'+convert(nvarchar(2),@compteur),\r\n\t\t\t\tgetdate()\r\n\tselect @compteur+=1\r\nend<\/pre>\n<p><a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/Showplan.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-268\" title=\"Showplan\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/Showplan-1024x343.jpg\" alt=\"\" width=\"620\" height=\"207\" srcset=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/Showplan-1024x343.jpg 1024w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/Showplan-300x100.jpg 300w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/Showplan.jpg 1265w\" sizes=\"auto, (max-width: 620px) 100vw, 620px\" \/><\/a><\/p>\n<p>Et c\u2019est justement dans une mauvaise compr\u00e9hension de ce mode de d\u00e9clenchement que r\u00e9sident souvent quelques bugs.<br \/>\nDans le cas pr\u00e9sent, lors de l\u2019insertion d\u2019un nouvel enregistrement dans la table Sales.Currency, la valeur de la colonne Name est stock\u00e9e dans une variable @Name, dont la longueur est ensuite d\u00e9termin\u00e9e, et si cette longueur est inf\u00e9rieure \u00e0 5 alors le syst\u00e8me signale une erreur et l\u2019insertion est refus\u00e9e.<br \/>\n<a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/UnitaireKO.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-269\" title=\"UnitaireKO\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/UnitaireKO.jpg\" alt=\"\" width=\"604\" height=\"130\" srcset=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/UnitaireKO.jpg 604w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/UnitaireKO-300x64.jpg 300w\" sizes=\"auto, (max-width: 604px) 100vw, 604px\" \/><\/a><br \/>\nMais que se passe-t-il lorsque plusieurs enregistrements sont ins\u00e9r\u00e9s en une seule instruction ?<br \/>\n<a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/ErreurCachee.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-270\" title=\"ErreurCachee\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/ErreurCachee.jpg\" alt=\"\" width=\"455\" height=\"187\" srcset=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/ErreurCachee.jpg 455w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/ErreurCachee-300x123.jpg 300w\" sizes=\"auto, (max-width: 455px) 100vw, 455px\" \/><\/a><br \/>\nOn remarque ici qu\u2019un enregistrement incorrect s\u2019est gliss\u00e9 au milieu du lot et n\u2019a pas \u00e9t\u00e9 intercept\u00e9 par le d\u00e9clencheur. La raison en est simple : le code du d\u00e9clencheur a \u00e9t\u00e9 ex\u00e9cut\u00e9 une et une seule fois lors de l\u2019instruction INSERT (et non pas une fois par ligne ins\u00e9r\u00e9e). La valeur de la variable @Name n\u2019a donc pas sp\u00e9cialement \u00e9t\u00e9 ma\u00eetris\u00e9e (en fait, c\u2019est la valeur de la premi\u00e8re ligne qui a \u00e9t\u00e9 prise en compte). Et au final, le d\u00e9clencheur semble de pas avoir fait son travail.<br \/>\nEn fait, il ne faut pas oublier ce que repr\u00e9sente \u00ab inserted \u00bb dans le d\u00e9clencheur. Il s\u2019agit d\u2019une table contenant les valeurs ins\u00e9r\u00e9es, avec les colonnes correspondant \u00e0 la table Sales.Currency, mais surtout avec autant de lignes qu\u2019il se doit pour d\u00e9crire l\u2019ensemble de l\u2019impact de l\u2019instruction INSERT, et il ne faut surtout pas oublier que l\u2019instruction INSERT permet tout \u00e0 fait d\u2019ins\u00e9rer plusieurs lignes d\u2019un coup. Il s\u2019agit donc de modifier le code du trigger pour prendre en compte cet \u00e9tat de fait, et faire en sorte que le d\u00e9clencheur joue son r\u00f4le non seulement pour les insertions unitaires, mais aussi pour les insertions multiples.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"sql\">ALTER TRIGGER Sales.trigCurrency\r\n   ON  Sales.Currency\r\n   AFTER INSERT\r\nAS\r\nBEGIN\r\n\tIF EXISTS (select *\r\n\t\t\t\tfrom inserted\r\n\t\t\t\twhere len(Name) &lt; 5)\r\n\tBEGIN\r\n\t\tROLLBACK TRANSACTION\r\n\tEND\r\nEND<\/pre>\n<p>Et cette fois-ci, plus moyen de cacher une valeur incorrecte au milieu d\u2019un lot de bonnes donn\u00e9es !<br \/>\n<a href=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/DetectionOK.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-271\" title=\"DetectionOK\" src=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/DetectionOK.jpg\" alt=\"\" width=\"591\" height=\"188\" srcset=\"https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/DetectionOK.jpg 591w, https:\/\/www.sqlserver.fr\/blog\/wp-content\/uploads\/2012\/03\/DetectionOK-300x95.jpg 300w\" sizes=\"auto, (max-width: 591px) 100vw, 591px\" \/><\/a><br \/>\nD\u2019une mani\u00e8re g\u00e9n\u00e9rale, on peut dire qu\u2019\u00e0 partir du moment o\u00f9 l\u2019on se met \u00e0 d\u00e9clarer des variables dans un d\u00e9clencheur, il y a de fortes chances que l\u2019on ait impl\u00e9ment\u00e9 un code qui g\u00e8re les donn\u00e9es de mani\u00e8re unitaire et oublie totalement le fait que les instructions SQL peuvent manipuler plusieurs enregistrements d\u2019un coup. Donc ne fuyez pas forc\u00e9ment les d\u00e9clencheurs, mais soyez vigilants dans leur impl\u00e9mentation\u2026<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Suivant les exp\u00e9riences et sensibilit\u00e9s de chacun, les D\u00e9clencheurs (Triggers en anglais) sont accept\u00e9s et utilis\u00e9s par certains, ou fuis comme la peste par d\u2019autres. Outre l\u2019architecture technique permettant parfois d\u2019exclure les codages sous forme de d\u00e9clencheurs, il est aussi &hellip; <a href=\"https:\/\/www.sqlserver.fr\/blog\/trigger-ensembliste\/\">Continuer la lecture <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":7,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-267","post","type-post","status-publish","format-standard","hentry","category-article_sql"],"_links":{"self":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/267","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/users\/7"}],"replies":[{"embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/comments?post=267"}],"version-history":[{"count":14,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/267\/revisions"}],"predecessor-version":[{"id":1967,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/posts\/267\/revisions\/1967"}],"wp:attachment":[{"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/media?parent=267"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/categories?post=267"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.sqlserver.fr\/blog\/wp-json\/wp\/v2\/tags?post=267"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}