Cours Trigger
Cours Trigger
base de données II
Filière : TDI2
Les déclencheurs peuvent effectuer des modifications en cascade dans des tables
associées de la base de données, mais ces modifications peuvent être exécutées plus
efficacement par le biais de contraintes d'intégrité référentielle en cascade.
Pour assurer l'application de restrictions plus complexes que celles définies à l'aide de
contraintes CHECK.
Contrairement aux contraintes CHECK, ils peuvent faire référence à des colonnes
d'autres tables. Par exemple, un déclencheur peut utiliser une instruction SELECT à
partir d'une autre table afin de comparer avec les données insérées ou mises à jour et
d'effectuer des actions supplémentaires, comme modifier les données ou afficher un
message d'erreur défini par l'utilisateur.
Pour détecter la différence entre l'état d'une table avant et après une modification des
données, et entreprendre une ou plusieurs actions en fonction de cette différence.
Plusieurs déclencheurs du même type (INSERT, UPDATE ou DELETE) sur une table,
permettent que de nombreuses actions différentes soient réalisées en réponse à la
même instruction de modification.
Les contraintes et les déclencheurs possèdent leurs avantages spécifiques, utiles dans des
situations particulières. Le principal avantage des déclencheurs est qu'ils peuvent contenir une
logique de traitement complexe utilisant du code Transact-SQL. Si les déclencheurs peuvent
ainsi prendre en charge toutes les fonctionnalités des contraintes, ils ne constituent pas pour
autant la meilleure méthode à utiliser dans tous les cas.
L'intégrité d'entité doit toujours être appliquée au niveau le plus bas par des index qui font
partie de contraintes PRIMARY KEY et UNIQUE, ou qui sont créés indépendamment des
contraintes. L'intégrité de domaine doit être appliquée au moyen de contraintes CHECK, et
l'intégrité référentielle (RI) (RI, referential integrity), par des contraintes FOREIGN KEY, en
admettant que les fonctionnalités qu'ils offrent correspondent aux besoins fonctionnels de
l'application.
Les déclencheurs sont particulièrement utiles lorsque les fonctionnalités prises en charge par
les contraintes ne peuvent pas répondre aux besoins fonctionnels de l'application. Exemple :
Les contraintes FOREIGN KEY peuvent valider une valeur de colonne uniquement si
celle-ci correspond exactement à une valeur d'une autre colonne, à moins que la clause
REFERENCES définisse une action d'intégrité référentielle en cascade.
Une contrainte CHECK ne peut valider une valeur de colonne que par rapport à une
expression logique ou à une autre colonne de la même table. Vous devez utiliser un
déclencheur si votre application requiert qu'une valeur de colonne soit validée par
rapport à une colonne d'une autre table.
Les contraintes ne peuvent donner d'informations sur les erreurs qu'à travers les
messages d'erreur système standard. Si votre application requiert (ou peut tirer parti)
des messages personnalisés et une gestion des erreurs plus complexe, vous devez
utiliser un déclencheur.
Les déclencheurs peuvent effectuer des modifications en cascade dans des tables associées de
la base de données, mais ces modifications peuvent être exécutées plus efficacement par le
biais de contraintes d'intégrité référentielle en cascade.
Les déclencheurs peuvent servir à interdire ou à annuler (roll back) des modifications
qui enfreignent l'intégrité référentielle, annulant ainsi la tentative de modification des
données. Un déclencheur de ce type peut entrer en action si vous modifiez une clé
étrangère et que la nouvelle valeur ne correspond pas à sa clé primaire. Par exemple,
vous pouvez créer, sur titleauthor.title_id, un déclencheur d'insertion qui annule toute
insertion si la nouvelle valeur ne correspond pas à une valeur de titles.title_id. Les
contraintes de clé étrangère sont généralement utilisées dans ce but.
Si des contraintes existent sur la table du déclencheur, elles sont vérifiées après
l'exécution du déclencheur INSTEAD OF mais avant celle du déclencheur AFTER. Si
les contraintes sont violées, les actions du déclencheur INSTEAD OF sont annulées et
le déclencheur AFTER n'est pas exécuté.
Les déclencheurs AFTER sont exécutés après l'action associée à une instruction
INSERT, UPDATE ou DELETE. La définition du déclencheur AFTER s'effectue de
la même façon que celle de FOR, unique option disponible dans les versions
antérieures de SQL Server. Les déclencheurs AFTER peuvent être spécifiés
uniquement sur des tables.
Chaque table ou vue peut disposer d'un seul déclencheur INSTEAD OF par action de
déclenchement (UPDATE, DELETE et INSERT). Une table peut en revanche détenir
plusieurs déclencheurs AFTER par action de déclenchement.
Exemple
A. Utilisation du déclencheur INSTEAD OF pour remplacer l'action de déclenchement standard
CREATE TRIGGER TableAInsertTrig ON TableA
INSTEAD OF INSERT
AS ...
Si un déclencheur INSTEAD OF défini sur une table exécute une instruction portant sur cette
table et susceptible de l'activer de nouveau, il n'est pas appelé de façon récurrente.
L'instruction est traitée comme si la table ne détenait aucun déclencheur INSTEAD OF et
démarre la chaîne des opérations de contrainte et des exécutions du déclencheur AFTER. Par
exemple, si un déclencheur est défini sur une table comme déclencheur d'insertion INSTEAD
OF (INSERT) et qu'il exécute une instruction INSERT sur cette table, cette instruction
INSERT ne l'appelle pas une seconde fois. L'instruction INSERT exécutée par le déclencheur
démarre le processus d'exécution des actions de contrainte et d'activation de tout déclencheur
d'insertion AFTER (INSERT) défini pour la table.
Remarque L'utilisation de curseurs dans les déclencheurs n'est pas recommandée, car
cela peut porter préjudice aux performances. Au lieu des curseurs, utilisez une logique
basée sur un ensemble de lignes afin de concevoir un déclencheur portant sur plusieurs
lignes.
ne pas traiter une partie d'un lot et consigner dans le journal les lignes problématiques
;
Les insertions en double dans la table Person sont ignorées, et les informations issues
des insertions sont consignées dans la table PersonDuplicates.
Les instructions Transact-SQL créent deux tables de base, une vue, une table d'enregistrement
des erreurs et le déclencheur INSTEAD OF sur la vue. Ces tables séparent les données
personnelles et d'entreprise et elles représentent les tables de base pour la vue :
La vue suivante indique toutes les données pertinentes relatives à une personne issues des
deux tables :
Vous pouvez enregistrer les tentatives d'insertion de lignes présentant des numéros de sécurité
sociale dupliqués. La table PersonDuplicates consigne les valeurs insérées, l'ID de
l'utilisateur à l'origine de la tentative d'insertion et l'heure de l'insertion :
Le déclencheur INSTEAD OF insère des lignes dans des tables de base multiples à partir
d'une simple vue. Les tentatives d'insertion de lignes présentant des numéros de sécurité
sociale dupliqués sont enregistrées dans la table PersonDuplicates. Les lignes dupliquées
dans la table EmployeeTable sont modifiées en instructions de mise à jour.
L'instruction CREATE TRIGGER doit être la première instruction du lot. Toutes les
autres instructions qui suivent dans ce lot sont interprétées comme faisant partie de la
définition de l'instruction CREATE TRIGGER.
Vous pouvez créer un déclencheur uniquement dans la base de données en cours, mais
un déclencheur peut référencer des objets situés hors de celle-ci.
Bien que les déclencheurs puissent faire référence à des tables temporaires, ils ne
peuvent pas être créés sur une table système ou temporaire. Les tables système ne
doivent pas être référencées ; utilisez plutôt les vues de schéma d'information.
Bien qu'une instruction TRUNCATE TABLE ait les mêmes effets qu'une instruction
DELETE dépourvue de clause WHERE (elle supprime toutes les lignes), elle ne peut
pas activer les déclencheurs DELETE du fait que l'instruction TRUNCATE TABLE
n'est pas inscrite au journal.
son nom ;
les instructions de modification des données qui l'activent, les options valides étant
INSERT, UPDATE ou DELETE (un même déclencheur peut être activé par plusieurs
instructions de modification des données, Ainsi, un déclencheur peut être activé
simultanément par les instructions INSERT et UPDATE.
Déclencheurs multiples
Une table peut comporter plusieurs déclencheurs d'un type donné, à condition que ceux-ci
portent des noms différents, et chaque déclencheur peut exécuter de nombreuses fonctions.
Toutefois, un déclencheur donné ne peut porter que sur une seule table mais il peut s'appliquer
à n'importe quel sous-ensemble de trois actions utilisateur (UPDATE, INSERT et DELETE).
Une table ne peut posséder qu'un seul déclencheur INSTEAD OF d'un type donné.
Les autorisations CREATE TRIGGER reviennent par défaut au propriétaire de la table sur
laquelle est défini le déclencheur, au rôle de serveur fixe sysadmin et aux membres des rôles
Si un déclencheur INSTEAD OF est créé sur une vue, la chaîne d'appartenance est rompue si
le propriétaire de la vue ne possède pas également les tables de base référencées par la vue et
le déclencheur. Si une table de base n'est pas détenue par le propriétaire de la vue, le
propriétaire de la table doit accorder séparément les autorisations nécessaires à tout utilisateur
effectuant des opérations de lecture ou de mise à jour sur la vue. Si un même utilisateur est le
propriétaire de la vue mais aussi des tables de base sous-jacentes, les autorisations qu'il
accorde aux autres utilisateurs ne peuvent porter que sur la vue, et non sur telle ou telle table
de base.
3. Dans le volet de détails, cliquez avec le bouton droit sur la table dans laquelle vous
allez créer le déclencheur, pointez sur Toutes les tâches, puis cliquez sur Gérer les
déclencheurs.
5. Dans la boîte Texte, entrez le texte du déclencheur. Utilisez les touches CTRL-TAB
pour créer un alinéa dans le texte du déclencheur.
Important Les instructions DISK RESIZE, DISK INIT, LOAD DATABASE et LOAD
LOG ont été préservées dans Microsoft® SQL Server 2000™ uniquement à des fins de
compatibilité ascendante et ne figureront peut-être plus dans les versions futures.
Si vous voulez vous assurer que les autres utilisateurs ne peuvent pas voir la définition d'un
déclencheur, vous pouvez utiliser la clause WITH ENCRYPTION. La définition du
déclencheur est alors enregistrée dans un format illisible.
Une fois cryptée, la définition du déclencheur ne peut être décryptée ni affichée par personne,
pas même son propriétaire ni l'administrateur système.
SET QUOTED_IDENTIFIER ON ;
SET ANSI_DEFAULTS ON ;
Ces paramètres améliorent la portabilité des applications ODBC. Étant donné que les
applications DB-Library– ne définissent généralement pas ces options, les déclencheurs
doivent être testés avec les options SET indiquées ci-dessus, à la fois activées (ON) et
désactivées (OFF). Cette opération garantit que les déclencheurs fonctionnent correctement,
quelles que soient les options activées par une connexion déterminée lors de l'appel du
déclencheur. Un déclencheur qui requiert un paramétrage particulier pour une de ces options
devra commencer par une instruction SET. Cette instruction SET n'est active que pour
l'exécution du déclencheur ; à la fin de celle-ci, la configuration d'origine est restaurée.
La clause IF UPDATE (column_name) peut être utilisée dans la définition d'un déclencheur
pour déterminer si une instruction INSERT ou UPDATE a modifié une colonne particulière
de la table. Cette clause prend la valeur TRUE si une valeur est attribuée à la colonne.
Remarque Étant donné qu'une valeur spécifique d'une colonne ne peut pas être
supprimée par l'instruction DELETE, la clause IF UPDATE ne s'applique pas à
l'instruction DELETE.
Vous pouvez aussi utiliser la clause IF COLUMNS_UPDATED() pour vérifier les colonnes
de la table qui ont été mises à jour par une instruction INSERT ou UPDATE. Cette clause
utilise un masque de bits (binaire) entier pour spécifier les colonnes à tester.
Exemple
SQL Server permet à un déclencheur de référencer une table qui n'existait pas au moment où
le déclencheur a été créé. Cette fonction s'appelle la résolution de noms différée.
Renvoi de résultats
/* Start of Batch */
INSERT employee VALUES ('XYZ12345M', 'New', 'M', 'Employee', 1, 1, '9952',
'6/1/95') -- Causes trigger to fire and ROLLBACK TRANSACTION.
DELETE employee WHERE emp_id = 'PMA42628M'
GO
/* Start of Transaction */
BEGIN TRANSACTION
UPDATE employee SET hire_date = '7/1/94' WHERE emp_id = 'VPA30890F'
INSERT employee VALUES ('XYZ12345M', 'New', 'M', 'Employee', 1, 1, '9952',
'6/1/95') -- Causes trigger to fire and ROLLBACK TRANSACTION
Les tables inserted et deleted sont principalement utilisées dans les déclencheurs pour :
insérer ou mettre à jour des données dans des tables de base sous-jacentes d'une vue ;
Détecter la différence entre l'état d'une table avant et après une modification des
données, et entreprendre une ou plusieurs actions en fonction de cette différence.
La table deleted stocke des copies des lignes affectées par les instructions DELETE et
UPDATE. Pendant l'exécution d'une instruction DELETE ou UPDATE, certaines lignes sont
La table inserted stocke des copies des lignes affectées par les instructions INSERT et
UPDATE. Durant une transaction INSERT ou UPDATE, de nouvelles lignes sont ajoutées
simultanément dans la table inserted et dans la table du déclencheur. Les lignes de la table
inserted sont des copies des lignes créées dans la table du déclencheur.
D'un point de vue théorique, une transaction UPDATE est une opération de suppression suivie
d'une opération d'insertion ; les anciennes lignes sont d'abord copiées dans la table deleted, et
les nouvelles lignes sont ensuite copiées dans la table du déclencheur et dans la table
inserted.
Pour définir les conditions du déclencheur, utilisez les tables inserted et deleted de façon
appropriée, en fonction de l'action qui a activé le déclencheur. Bien que vous puissiez, sans
provoquer d'erreur, référencer la table deleted pendant le test d'une insertion (INSERT) ou la
table inserted pendant le test d'une suppression (DELETE), ces tables de test du déclencheur
ne contiendront alors aucune ligne.
SQL Server 2000 ne permet pas le référencement aux colonnes text, ntext ou image dans les
tables inserted et deleted pour les déclencheurs AFTER ; toutefois ces références de colonnes
sont autorisées pour les déclencheurs INSTEAD OF. Pour plus d'informations, voir CREATE
TRIGGER.
Les tables inserted et deleted transmises aux déclencheurs INSTEAD OF définis sur des
tables suivent les mêmes règles que les tables inserted et deleted transmises aux déclencheurs
AFTER. Le format des tables inserted et deleted est le même que celui de la table sur
laquelle est défini le déclencheur INSTEAD OF. Chaque colonne des tables inserted et
deleted est directement mappée vers une colonne de la table de base.
Qu'une table possède ou non un déclencheur INSTEAD OF, les règles qui régissent la
fourniture de valeurs pour les colonnes par une instruction INSERT ou UPDATE faisant
référence à la table sont les mêmes :
Aucune valeur ne peut être spécifiée pour une colonne calculée ou de type de données
timestamp.
Aucune valeur ne peut être spécifiée pour une colonne dotée d'une propriété
IDENTITY, sauf si le paramètre IDENTITY_INSERT de cette colonne est activé
(ON), auquel cas les instructions INSERT doivent fournir une valeur.
Les valeurs sont facultatives pour toute colonne acceptant des valeurs NULL ou toute
colonne NOT NULL avec valeur par défaut (DEFAULT), sous réserve qu'il ne
s'agisse pas d'une colonne calculée, identité ou timestamp.
Lorsqu'une instruction INSERT, UPDATE ou DELETE fait référence à une vue possédant un
déclencheur INSTEAD OF, le moteur de base de données appelle le déclencheur au lieu
d'effectuer une opération directe sur une table. Le déclencheur doit utiliser les informations
présentées dans les tables inserted et deleted pour élaborer toute instruction nécessaire à
l'implémentation de l'action requise dans les tables de base, même si le format des
informations contenues dans les tables inserted et deleted conçues pour la vue diffère de
celui des données stockées dans les tables de base.
Le format des tables inserted et deleted transmises à un déclencheur INSTEAD OF défini sur
une vue correspond à la liste de sélection de l'instruction SELECT définie pour la vue.
Exemple :
L'ensemble de résultats pour cette vue possède trois colonnes : une colonne int et deux
colonnes nvarchar. Les tables inserted et deleted transmises à un déclencheur INSTEAD OF
défini sur la vue possèdent également une colonne int nommée EmployeeID et deux colonnes
nvarchar, l'une nommée LName et l'autre, FName.
La liste de sélection d'une vue peut également contenir des expressions qui n'établissent pas
de mappage direct vers une colonne de table de base unique. Certaines expressions de vue,
telles que l'invocation d'une constante ou d'une fonction, peuvent ne pas référencer de colonne
et être ignorées. Les expressions complexes peuvent référencer plusieurs colonnes, mais les
tables inserted et deleted ne détiennent qu'une seule valeur pour chaque ligne insérée. Les
mêmes considérations s'appliquent aux expressions simples d'une vue si elles font référence à
une colonne calculée à laquelle est associée une expression complexe. Un déclencheur
INSTEAD OF défini sur la vue doit gérer ces types d'expressions.
Considérations multilignes
Un point important dont il faut tenir compte, lors de l'écriture du code d'un déclencheur, est
que l'instruction qui active le déclencheur peut être une instruction unique affectant plusieurs
lignes de données au lieu d'une seule. Il en est généralement ainsi pour les déclencheurs de
mise à jour (UPDATE) et de suppression (DELETE) qui concernent souvent plusieurs lignes.
Cela est moins fréquent dans le cas des déclencheurs d'insertion (INSERT) car l'instruction
INSERT de base n'ajoute qu'une seule ligne. Toutefois, comme un déclencheur d'insertion
peut être activé par une instruction SELECT INSERT INTO (table_name), l'insertion de
nombreuses lignes peut aboutir à un appel de déclencheur unique.
Remarque L'utilisation de curseurs dans les déclencheurs n'est pas recommandée, car
cela peut porter préjudice aux performances. Au lieu des curseurs, utilisez une logique
basée sur un ensemble de lignes afin de concevoir un déclencheur portant sur plusieurs
lignes.
Exemple
Les déclencheurs des exemples suivants ont pour mission de stocker le total cumulé d'une
colonne dans une autre table.
UPDATE titles
SET ytd_sales = ytd_sales + qty
FROM inserted
WHERE titles.title_id = inserted.title_id
Dans le cas d'une insertion (INSERT) multiligne, ce déclencheur peut ne pas fonctionner
correctement ; l'expression à droite d'une expression d'affectation dans une instruction
UPDATE (ytd_sales + qty) ne peut être qu'une unique valeur, et non une liste de valeurs. Le
déclencheur obtient donc une valeur à partir d'une seule ligne de la table inserted et l'ajoute à
la valeur ytd_sales existante de la table titles pour une valeur donnée de title_id. Le résultat
risque de ne pas être correct si une valeur unique de title_id se trouve plus d'une fois dans la
table inserted.
Pour mettre à jour correctement la table titles, le déclencheur doit tenir compte de l'existence
possible de plusieurs lignes dans la table inserted. Vous pouvez pour cela recourir à la
fonction SUM, qui calcule la valeur qty totale d'un groupe de lignes de la table inserted pour
chaque valeur title_id. La fonction SUM est placée dans une sous-requête en corrélation
(l'instruction SELECT entre parenthèses) qui renvoie une valeur unique pour chaque valeur
UPDATE titles
SET ytd_sales = ytd_sales +
(SELECT SUM(qty) -- Correlated subquery.
FROM inserted
WHERE titles.title_id = inserted.title_id)
WHERE titles.title_id IN
(SELECT title_id FROM inserted)
Pour rectifier ce problème, vous pouvez modifier le déclencheur afin d'utiliser la méthode
optimale en fonction du nombre de lignes. Par exemple, la fonction @@ROWCOUNT peut
être utilisée dans la logique du déclencheur pour différencier une insertion d'une seule ligne
d'une insertion de plusieurs lignes.
Exemple
A. Utilisation d'un déclencheur AFTER INSERT
L'exemple suivant suppose l'existence d'une table nommée newsale dans la base de données
pubs. Voici l'instruction CREATE pour newsale :
Si vous voulez examiner chacun des enregistrements que vous voulez insérer, le déclencheur
conditionalinsert analyse l'insertion ligne par ligne, puis supprime les lignes qui n'ont pas de
valeur title_id correspondante dans la table titles.
La transaction n'est pas annulée dans sa totalité si des titres non valables ont été insérés ; dans
ce cas, le déclencheur supprime les lignes incorrectes. Cette capacité de supprimer des lignes
qui ont été insérées repose sur l'ordre dans lequel le traitement s'effectue lors de l'activation
des déclencheurs. D'abord, les lignes sont insérées dans la table sales et dans la table inserted,
puis le déclencheur s'exécute.
Pour tester le déclencheur, insérez quatre lignes dans la table newsale. Les title_ids de deux
lignes de cette table ne correspondent pas aux valeurs spécifiées dans la table titles.
newsale
stor_id ord_num date qty payterms title_id
------- -------- ------------------- --- -------- --------
7066 QA7442.3 Jul 25 1995 8:35AM 75 Net 30 PS1372
7066 QA7442.3 Jul 24 1995 8:35AM 75 Net 60 BU7832
Ensuite, insérez des données de la table newsale dans la table sales. L'instruction est la
suivante :
INSERT sales
SELECT * FROM newsale
Les lignes title_id PSxxxx et PSyyyy ne correspondent à aucune ligne de la table titles et le
déclencheur conditionalinsert supprime ces deux lignes des tables sales et inserted.
Premier
qui définit le déclencheur comme étant le premier déclencheur AFTER activé dans le
cadre d'une action de déclenchement ;
Dernier
qui définit le déclencheur comme étant le dernier déclencheur AFTER activé dans le
cadre d'une action de déclenchement ;
Aucun
qui spécifie qu'aucun rang d'exécution n'est affecté au déclencheur, option servant
essentiellement à réinitialiser un déclencheur défini comme étant le premier ou le
dernier déclencheur.
Une table peut, à un moment donné, comporter plusieurs déclencheurs INSERT, UPDATE et
DELETE. Chaque type d'instruction peut posséder des premier et dernier déclencheurs qui lui
sont propres, et doivent cependant être différents.
Un déclencheur INSTEAD OF ne peut pas être défini en tant que premier ou dernier
déclencheur. Il est activé avant que l'apport de mises à jour aux tables sous-jacentes.
Toutefois, si des mises à jour sont apportées par un déclencheur INSTEAD OF à des tables
sous-jacentes, elles se produisent après les déclencheurs définis sur la table, y compris le
premier déclencheur. Par exemple, si un déclencheur INSTEAD OF sur une vue met à jour
une table de base contenant trois déclencheurs, ces trois déclencheurs sont activés avant
l'insertion des données par le déclencheur INSTEAD OF.
Si une instruction ALTER TRIGGER vise à modifier un déclencheur défini comme le premier
ou le dernier, l'attribut first ou last est supprimé et le rang d'exécution prend pour valeur none
; le rang d'exécution doit être réinitialisé avec sp_settriggerorder.
La réplication génère un premier déclencheur automatiquement pour toute table qui est un
abonné avec mise à jour immédiate ou en attente. Elle nécessite un déclencheur qui soit le
premier. Elle génère une erreur si vous essayez d'affecter l'attribut d'abonné avec mise à jour
immédiate ou en attente à une table détenant un premier déclencheur. Si vous affectez
l'attribut de premier déclencheur à un déclencheur défini par l'utilisateur après avoir fait d'une
table un abonné avec mise à jour immédiate ou en attente, sp_settriggerorder renvoie une
erreur. Si vous utilisez ALTER sur le déclencheur de réplication ou si, à l'aide de
sp_settriggerorder, vous définissez son rang d'exécution sur aucun ou dernier, l'abonnement
ne fonctionnera pas correctement.
Déclencheurs imbriqués
Les déclencheurs sont imbriqués lorsqu'un déclencheur exécute une action qui active un autre
déclencheur, lequel à son tour peut en activer un autre, et ainsi de suite. Les déclencheurs
peuvent être imbriqués sur 32 niveaux au maximum, et vous pouvez vérifier si l'imbrication
est autorisée au moyen de l'option de configuration de serveur nested triggers.
Si l'imbrication est permise et qu'un déclencheur de la chaîne démarre une boucle infinie, le
niveau d'imbrication maximal est dépassé et le déclencheur s'arrête.
Les déclencheurs imbriqués peuvent s'avérer utiles pour effectuer certaines opérations,
comme stocker une copie de sauvegarde de lignes modifiées par un déclencheur précédent.
Par exemple, vous pouvez créer un déclencheur sur titleauthor, qui effectue une copie de
sauvegarde des lignes de la colonne titleauthor qui ont été supprimées par le déclencheur
delcascadetrig . Lorsque le déclencheur déclencheur_suppression_cascade est activé, la
suppression de la ligne id_titre PS2091 de la table titres supprime la ou les lignes
correspondantes dans titreauteur. Pour enregistrer les données, créez un déclencheur
DELETE sur titleauthor qui stocke les données supprimées dans une autre table, del_save,
créée séparément. Exemple :
Il n'est pas recommandé d'utiliser des déclencheurs imbriqués dans une séquence où l'ordre a
de l'importance. Employez des déclencheurs séparés pour effectuer des modifications de
données en cascade.
Déclencheurs récursifs
la récursion directe ;
Elle se produit lorsqu'un déclencheur est activé et exécute une action qui l'active de
nouveau. Prenons l'exemple d'une application qui met à jour la table T3, ce qui active
le déclencheur Trig3. Trig3 met à jour de nouveau la table T3, ce qui active encore le
déclencheur Trig3.
la récursion indirecte ;
Elle se produit lorsqu'un déclencheur est activé et exécute une action qui active un
déclencheur sur une autre table. Le second déclencheur active une mise à jour de la
table d'origine, ce qui a pour effet d'activer une nouvelle fois le déclencheur d'origine.
Par exemple, une application met à jour la table T1, ce qui active le déclencheur
Trig1. Trig1 met à jour la table T2, ce qui active le déclencheur Trig2. Trig2 à son
tour met à jour la table T1 ce qui active de nouveau le déclencheur Trig1.
Exemple
A. Utilisation de déclencheurs récursifs pour résoudre des relations d'auto-référence
Une des utilisations des déclencheurs récursifs concerne les tables ayant une relation d'auto-
référence, également appelé fermeture transitive. Par exemple, la table emp_mgr définit :
Un déclencheur de mise à jour récursif peut être utilisé pour maintenir à jour la colonne
NoOfReports au fur et à mesure de l'insertion de l'enregistrement de nouveaux employés. Le
déclencheur d'insertion met à jour la colonne NoOfReports de l'enregistrement du
responsable, provoquant la mise à jour récursive de la colonne NoOfReports des autres
enregistrements en remontant la hiérarchie.
USE pubs
GO
-- Turn recursive triggers ON in the database.
ALTER DATABASE pubs
SET RECURSIVE_TRIGGERS ON
GO
CREATE TABLE emp_mgr (
emp char(30) PRIMARY KEY,
mgr char(30) NULL FOREIGN KEY REFERENCES emp_mgr(emp),
NoOfReports int DEFAULT 0
)
GO
CREATE TRIGGER emp_mgrins ON emp_mgr
FOR INSERT
AS
DECLARE @e char(30), @m char(30)
DECLARE c1 CURSOR FOR
SELECT emp_mgr.emp
FROM emp_mgr, inserted
WHERE emp_mgr.emp = [Link]
OPEN c1
FETCH NEXT FROM c1 INTO @e
WHILE @@fetch_status = 0
BEGIN
UPDATE emp_mgr
SET emp_mgr.NoOfReports = emp_mgr.NoOfReports + 1 -- Add 1 for newly
WHERE emp_mgr.emp = @e -- added employee.
UPDATE emp_mgr
SET emp_mgr.NoOfReports = emp_mgr.NoOfReports - 1 -- Decrement mgr's
2. Cliquez avec le bouton droit sur un serveur, puis cliquez sur Propriétés.
2. Développez le dossier Bases de données, cliquez avec le bouton droit sur la base de
données à modifier, puis cliquez sur Propriétés.
Les déclencheurs INSTEAD OF peuvent être définis sur des tables ou des vues ; toutefois, les
déclencheurs INSTEAD OF sont plus utiles pour l'extension des types de mises à jour qu'une
vue peut prendre en charge. Par exemple, les déclencheurs INSTEAD OF peuvent permettre
de modifier des tables de base multiples au travers d'une vue ou de modifier des tables de base
contenant les colonnes suivantes :
colonnes calculées
colonnes d'identité
Les déclencheurs INSTEAD OF INSERT peuvent être définis sur une vue ou une table pour
remplacer l'action standard de l'instruction INSERT. Les déclencheurs INSTEAD OF
INSERT sont généralement définis sur une vue pour insérer des données dans une ou
plusieurs tables de base.
Les colonnes figurant dans la liste de sélection de la vue peuvent accepter ou refuser les
valeurs NULL. Si une colonne de la vue n'accepte pas de valeur NULL, une instruction
INSERT doit lui fournir des valeurs. Les colonnes d'une vue autorisent les valeurs NULL si
l'expression qui les définit comprend des éléments tels que :
des références à une colonne de table de base qui accepte les valeurs NULL ;
une fonction CASE ou COALESCE avec une sous-expression acceptant des valeurs
NULL ;
NULLIF.
Une instruction INSERT faisant référence à une vue sur laquelle est défini un déclencheur
INSTEAD OF INSERT doit fournir des valeurs pour toutes les colonnes de la vue qui
n'acceptent pas de valeur NULL, et notamment celles qui font référence à des colonnes de la
table de base pour lesquelles aucune valeur d'entrée ne peut être spécifiée :
Par exemple, lorsqu'une instruction INSERT doit spécifier une valeur pour une colonne de
vue qui correspond à une colonne calculée de la table de base, elle peut fournir une valeur
d'espace réservé. Le déclencheur INSTEAD OF peut ignorer la valeur fournie lorsqu'il
élabore l'instruction INSERT qui insère les valeurs dans la table de base.
Les instructions suivantes illustrent ce processus au travers de la création d'une table, d'une
vue et d'un déclencheur :
--Create a view that contains all columns from the base table.
CREATE VIEW InsteadView
AS SELECT PrimaryKey, Color, Material, ComputedCol
FROM BaseTable
GO
Une instruction INSERT qui fait directement référence à BaseTable ne peut pas fournir de
valeur pour les colonnes PrimaryKey et ComputedCol. Exemple :
--A correct INSERT statement that skips the PrimaryKey and ComputedCol
columns.
INSERT INTO BaseTable (Color, Material)
VALUES (N'Red', N'Cloth')
Cependant, les instructions INSERT qui font référence à InsteadView doivent fournir une
valeur pour PrimaryKey et ComputedCol :
La table inserted transmise à InsteadTrigger est conçue avec une colonne PrimaryKey et
ComputedCol n'acceptant pas de valeur NULL, si bien que l'instruction INSERT qui fait
référence à la vue doit fournir une valeur pour ces colonnes. Les valeurs 999 et N'XXXXXX'
sont transmises à InsteadTrigger, mais l'instruction INSERT du déclencheur ne sélectionne
pas [Link] ou [Link], si bien que les valeurs sont ignorées.
La ligne effectivement insérée dans BaseTable présente la valeur 2 dans PrimaryKey et
N'BluePlastic' dans ComputedCol.
Les valeurs contenues dans la table inserted pour les colonnes calculées, identité et
timestamp diffèrent selon que vous appliquez des déclencheurs INSTEAD OF INSERT
spécifiés sur des tables ou sur des vues.
Une instruction INSERT qui fait directement référence à une table de base n'a pas besoin de
fournir de valeurs pour une colonne NOT NULL dotée d'une valeur par défaut (DEFAULT).
Si elle ne fournit pas de valeur, la valeur par défaut (DEFAULT) est utilisée. Toutefois, si une
colonne NOT NULL possédant une valeur par défaut (DEFAULT) est référencée par une
expression simple dans une vue à laquelle est associé un déclencheur INSTEAD OF INSERT,
toute instruction INSERT faisant référence à la vue doit fournir une valeur pour la colonne.
Cette valeur est requise pour élaborer la table inserted transmise au déclencheur. Une
convention doit être adoptée quant à la valeur indiquant au déclencheur que la valeur par
défaut doit être utilisée. La meilleure convention consiste à ce que l'instruction INSERT
fournisse la valeur par défaut.
Les déclencheurs INSTEAD OF UPDATE peuvent être définis sur une vue ou une table pour
remplacer l'action standard de l'instruction UPDATE. Les déclencheurs INSTEAD OF
UPDATE sont généralement définis sur une vue pour modifier des données dans une ou
plusieurs tables de base.
Une instruction UPDATE qui fait référence à une vue dotée d'un déclencheur INSTEAD OF
UPDATE doit fournir des valeurs pour toutes les colonnes de vue n'acceptant pas de valeur
NULL et référencées dans la clause SET, et notamment celles qui font référence à des
colonnes de la table de base pour lesquelles aucune valeur d'entrée ne peut être spécifiée :
Généralement, lorsqu'une instruction UPDATE qui référence une table tente de définir la
valeur d'une colonne calculée, d'identité ou timestamp, une erreur est générée car les valeurs
de ces colonnes doivent être déterminées par Microsoft® SQL Server ™. Ces colonnes
doivent être incluses dans l'instruction UPDATE afin de satisfaire l'exigence NOT NULL de
la colonne. Toutefois, si l'instruction UPDATE référence une vue avec un déclencheur
INSTEAD OF UPDATE, la logique définie dans le déclencheur peut ignorer ces colonnes et
éviter l'erreur. Pour cela, le déclencheur INSTEAD OF UPDATE ne doit pas essayer de
mettre à jour les valeurs des colonnes correspondantes de la table de base. Cette opération
Un déclencheur INSTEAD OF UPDATE n'a pas besoin de traiter les données émanant de
colonnes inserted non mises à jour. Les colonnes de la table inserted transmise à un
déclencheur INSTEAD OF UPDATE et spécifiées dans la clause SET respectent les mêmes
règles que les colonnes inserted figurant dans un déclencheur INSTEAD OF INSERT.
Concernant les colonnes non spécifiées dans la clause SET, les valeurs contenues dans la table
inserted sont celles qui existaient avant l'émission de l'instruction UPDATE. Le déclencheur
peut tester si une colonne donnée a été mise à jour à l'aide de la clause IF
UPDATED(column).
Il doit utiliser les valeurs fournies pour les colonnes calculées, identité ou timestamp
uniquement dans les conditions de recherche d'une clause WHERE.
La logique que doit utiliser le déclencheur INSTEAD OF UPDATE d'une vue afin de traiter
les valeurs mises à jour fournies pour les colonnes calculées, identité, timestamp ou dotée
d'une valeur par défaut est la même que celle appliquée aux valeurs insérées pour ces types de
colonnes.
Remarque Les déclencheurs INSTEAD OF UPDATE ne peuvent pas être définis sur une
table qui a une clé étrangère définie avec une action UPDATE.
Les déclencheurs INSTEAD OF DELETE peuvent être définis sur une vue ou une table pour
remplacer l'action standard de l'instruction DELETE. Les déclencheurs INSTEAD OF
DELETE sont généralement définis sur une vue pour modifier des données dans une ou
plusieurs tables de base.
Les instructions DELETE ne spécifient pas de modifications pour les valeurs de données
existantes. Elles indiquent uniquement les lignes à supprimer. La table inserted transmise à
un déclencheur DELETE est toujours vide. La table deleted envoyée à un déclencheur
DELETE contient une image des lignes dans l'état où elles se trouvaient avant l'émission de
l'instruction UPDATE. Dans le cas d'un déclencheur INSTEAD OF DELETE créé sur une
vue, le format de la table deleted est basé sur celui de la liste de sélection définie pour la vue.
Remarque Les déclencheurs INSTEAD OF DELETE ne peuvent pas être définis sur une
table qui a une clé étrangère définie avec une action DELETE.
La liste de sélection d'une vue peut contenir des expressions autres que des expressions
simples composées uniquement d'un nom de colonne. Les déclencheurs INSTEAD OF créés
sur ces vues doivent posséder une logique telle qu'il leur soit possible de déterminer
les expressions de vue sans mappage vers une colonne d'une table quelle qu'elle soit,
telles qu'une constante ou certains types de fonctions ;
les expressions de vue avec mappage vers plusieurs colonnes, telles que les
expressions complexes qui résultent d'une concaténation de chaînes à partir de deux ou
de plusieurs colonnes ;
les expressions de vue qui transforment la valeur d'une seule colonne de la table de
base, comme dans le cas d'une référence à une colonne dans une fonction.
Ces considérations s'appliquent également aux colonnes de vue qui sont des expressions
simples faisant référence à une colonne calculée dans une table de base. L'expression qui
définit la colonne calculée peut présenter la même forme qu'une expression plus complexe
dans la liste de sélection de la vue.
Les vues peuvent contenir, dans leur liste de sélection, des expressions n'établissant de
mappage vers aucune colonne de la table de base :
Alors que la colonne TodaysDate n'est mappée vers aucune colonne de la table, SQL Server
doit créer une colonne TodaysDate dans la table inserted qu'il transmet à un déclencheur
INSTEAD OF défini sur ExpressionView. Toutefois, la colonne [Link]
acceptant les valeurs NULL, une instruction INSERT faisant référence à ExpressionView ne
doit pas forcément fournir une valeur pour cette colonne. Étant donné que l'expression
n'établit de mappage vers aucune colonne de table, le déclencheur peut ignorer toute valeur
fournie par l'insertion (INSERT) dans cette colonne.
La même approche doit s'appliquer aux expressions de vue simples faisant référence à des
colonnes calculées de tables de base et dont le résultat ne dépend d'aucune autre colonne :
Une logique similaire est requise pour traiter les colonnes de vue qui sont des expressions
simples faisant référence à des colonnes calculées dotées d'expressions complexes.
Certaines expressions de vue peuvent transformer la valeur d'une colonne de table de base,
par exemple en effectuant une opération mathématique ou en utilisant la colonne comme
paramètre de fonction. Dans ce cas, la logique du déclencheur INSTEAD OF INSERT peut
répondre à deux approches :
La convention peut établir que toutes les instructions INSERT fournissent la valeur
brute à placer dans la table de base, et la logique du déclencheur déplace la valeur de
la table inserted vers la table de base.
La convention peut établir que toutes les instructions INSERT fournissent la valeur
qui doit normalement être renvoyée par une opération SELECT appliquée à la vue,
auquel cas la logique du déclencheur doit inverser l'opération. Exemple :
Pour certaines expressions, telles que les expressions complexes utilisant des opérations
mathématiques comme l'addition et la soustraction, il peut s'avérer impossible pour les
utilisateurs de fournir une valeur qui permette au déclencheur d'élaborer des valeurs sans
ambiguïté pour les colonnes de la table de base de destination. Par exemple, si la liste de
sélection d'une vue contient l'expression IntColA + IntColB AS AddedColumns, que
représente la valeur 10 dans [Link] ? 10 est-il le résultat de 3 + 7, 2 + 8 ou
5 + 5 ? Il est impossible de déterminer, uniquement à partir de la valeur de
[Link], les valeurs à placer dans IntColA et IntColB.
En pareil cas, vous pouvez programmer le déclencheur de telle sorte qu'il utilise d'autres
sources d'informations pour déterminer les valeurs à définir dans les colonnes de la table de
base. La liste de sélection des vues dotées d'un déclencheur INSTEAD OF doit contenir
suffisamment d'informations pour l'élaboration des valeurs de toutes les colonnes non NULL
des tables de base modifiées par le déclencheur. Les données ne doivent pas toutes provenir
directement de la table inserted. Dans certains cas, les valeurs de la table inserted peuvent
être des valeurs de clé utilisées par le déclencheur pour extraire les données adéquates d'autres
tables de base.
Le type de données text, ntext ou image stocké dans les tables inserted et deleted varie
suivant l'action de déclenchement (INSERT, UPDATE ou DELETE) :
Dans le cas d'une instruction INSERT, la table inserted contient la nouvelle valeur de
la colonne text, ntext ou image. Aucune ligne ne figure dans la table deleted.
Dans le cas d'une instruction DELETE, aucune ligne ne figure dans la table inserted,
et les lignes de la table deleted contiennent les valeurs que détenait la colonne text,
ntext ou image avant l'exécution de l'instruction DELETE.
Dans le cas d'une instruction UPDATE qui ne modifie pas la valeur text, ntext ou
image, les lignes des tables inserted et deleted contiennent les mêmes valeurs pour
les colonnes text, ntext ou image.
Dans le cas d'une instruction UPDATE qui modifie la valeur text, ntext ou image, les
valeurs de données contenues dans la table deleted sont celles qui existaient avant que
l'instruction ne débute, tandis que celles de la table inserted reflètent toute
modification définie dans la clause SET.
une valeur NULL implicite est insérée dans une colonne car aucune définition
DEFAULT n'existe ;
une valeur par défaut est insérée dans une colonne car une définition DEFAULT
existe.
31 Proposé par :A BENDAOUD
Exemple
A. Activation de déclencheurs test avec des valeurs NULL et par défaut
Les exemples suivants montrent comment un déclencheur est affecté par des valeurs NULL
implicites et explicites. Une petite table est créée afin de contenir deux valeurs entières. Une
colonne peut contenir des valeurs NULL ; l'autre colonne contient une valeur par défaut. Un
déclencheur détecte lorsque les deux colonnes sont modifiées et affiche un message lors de
son activation. Une série d'instructions INSERT teste l'activation du déclencheur en insérant
des combinaisons de valeurs NULL implicites et explicites.
CREATE TABLE t1
(a int NULL, b int NOT NULL DEFAULT 99)
GO
--When two values are inserted, the UPDATE is TRUE for both columns and the
trigger is activated.
INSERT t1 (a, b)
VALUES (1, 2)
--When two values are updated, the UPDATE is TRUE for both columns and the
trigger is activated.
UPDATE t1
SET a = 1, b = 2
--When an explicit NULL is updated in column a, the UPDATE is TRUE for both
columns,the trigger is activated.
UPDATE t1
SET a = NULL, b = 2
--When column a is updated with an implicit NULL, the UPDATE is FALSE for
both columns and the trigger is not activated.
UPDATE t1
SET b = 2
--When column b is updated explicitly with the default value, the UPDATE is
TRUE for both columns and the trigger is activated.
UPDATE t1
SET a = 2, b = DEFAULT
Si vous changez le nom d'un objet référencé par un déclencheur, vous devez modifier le
déclencheur pour que sa définition fasse référence au nouveau nom de l'objet. Par conséquent,
avant de renommer un objet, affichez les dépendances de l'objet pour savoir si des
déclencheurs peuvent être concernés par la modification projetée.
Vous pouvez aussi renommer un déclencheur. Le nouveau nom doit se conformer aux règles
en vigueur pour les identificateurs. Un utilisateur peut uniquement renommer les déclencheurs
dont il est le propriétaire, mais le propriétaire de la base de données peut changer le nom des
déclencheurs de n'importe quel utilisateur. Le déclencheur à renommer doit se trouver dans la
base de données en cours.
3. Dans le volet de détails, cliquez avec le bouton droit sur la table dans laquelle se
trouve le déclencheur, pointez sur Toutes les tâches, puis cliquez sur Gérer les
déclencheurs.
3. Dans le volet de détails, cliquez avec le bouton droit sur la table à laquelle appartient
le déclencheur, pointez sur Toutes les tâches, puis cliquez sur Afficher les
dépendances.
4. Dans Objet, cliquez sur le nom du déclencheur dont vous souhaitez afficher les
dépendances.
obtenir des informations sur la définition d'un déclencheur s'il n'a pas été crypté
lorsqu'il a été créé ou modifié, ce qui peut être utile pour prendre connaissance des
instructions Transact-SQL utilisées ou pour comprendre comment il agit sur la table
pour laquelle il est défini ;
dresser la liste des objets utilisés par le déclencheur spécifié, informations notamment
utilisées pour identifier les objets dont l'éventuelle suppression ou modification aurait
une répercussion sur le déclencheur.
3. Dans le volet de détails, cliquez avec le bouton droit sur la table dans laquelle se
trouve le déclencheur, pointez sur Toutes les tâches, puis cliquez sur Gérer les
déclencheurs.
3. Dans le volet de détails, cliquez avec le bouton droit sur la table à laquelle appartient
le déclencheur, pointez sur Toutes les tâches, puis cliquez sur Afficher les
dépendances.
4. Dans Objet, cliquez sur le nom du déclencheur dont vous souhaitez afficher les
dépendances.
3. Dans le volet de détails, cliquez avec le bouton droit sur la table dans laquelle se
trouve le déclencheur, pointez sur Toutes les tâches, puis cliquez sur Gérer les
déclencheurs.
CORRECTION
IF @ColumnList IS NULL
RAISERROR ('Aucune colonne de recherche trouvé dans la table %s',
RETURN
LBL_ERROR:
PRINT 'ERREUR LORS DE L''EXÉCUTION DE LA PROCÉDURE STOCKÉE
SP_SEARCH_STRING_ANYFIELD'
2-Il s'agit de donner la liste de tous les nombres premiers entre 1 et 5000.
Correction
SELECT * FROM #n
Une autre façon de faire est de travailler en logique ensembliste. Si nous disposons d'une
table des entiers, il est alors facile de comprendre que les nombres premiers sont tous
les nombres, moins ceux qui ne sont pas premiers... Il s'agit ni plus ni moins que de
réaliser une différence ensembliste.
Correction
Create porocedur nb-premier_ver2
As
CORRECTION
CREATE TRIGGER E_CLI_INS
UPDATE T_CLIENT
SET CLI_TEL = '01 02 03 04 05'
WHERE CLI_ID = 1
Serveur : Msg 8114, Niveau 16, État 5, Procédure E_CLI_INS, Ligne 6
Erreur de conversion du type de données varchar en numeric.
provoque une erreur et l'insertion n'a pas lieu.
UPDATE T_CLIENT
SET CLI_TEL = '[Link].95'
WHERE CLI_ID = 1
Le seul inconvénient est que cette façon de procéder rejette toutes les lignes insérées ou
mise à jour sans accepter celles qui peuvent être correctement formatées.
D'autre part on exécute cette procédure jusqu'au bout, même si la colonne CLI_TEL ne
subie aucune modification. Néanmoins ce cas peut être résolu par un traitement
spécifique utilisant la fonction UPDATE :
2- - L'exercice consiste maintenant à corriger à la volée des saisie incorrectes. Tous les
caractères de séparation tel que le tiret ou l'espace d'un numéro de téléphone devra être
convertis en point.
CORRECTION
UPDATE T_CLIENT
SET CLI_TEL = '88 77-66 55.44'
WHERE CLI_ID = 1
donne pour résultat :
Attention : le danger réside dans l'exécution récursive de tels triggers. Comme l'on
remet à jour la table à l'intérieur même du trigger, celui-ci est à nouveau déclenché. Le
phénomène, s'il n'était pas limité, pourrait provoquer une famine du processus. Il faut
donc veiller à le limiter. Dans ce sens SQL Server propose deux garde fous : le premier,
intrinsèque au serveur est de ne jamais dépasser 16 niveaux de récursion. Le second est
de proposer une limite plus restrictive à l'aide de la procédure sp_configure, qui permet
de modifier la variable nested triggers afin d'étendre les limites d'appel de triggers
imbriqués.
De plus pour connaître le niveau d'imbrication du trigger à l'intérieur de ce dernier il suffit
de lancer la fonction TRIGGER_NESTLEVEL() qui renvoie une variable de niveau.
Conseil : il est préférable de ne pas utiliser de triggers imbriqués et donc de laisser le
paramètre nested triggers de la configuration à 1.
3-Bien entendu ou pourrait être beaucoup plus fin dans ce genre de contrôle et analyser
puis remplacer, caractères par caractères.
A titre d’ exemple, nous allons réaliser un tel trigger :
-- variable de travail
DECLARE @IdCli int, @TelAvant VARCHAR(20), @TelApres VARCHAR(20),
@car CHAR(1), @i int, @j int
-- boucle de lecture
WHILE @@Fetch_Status = 0
BEGIN
-- si vide reboucle immédiatement
IF @TelAvant = ''
BEGIN
FETCH CurIns INTO @IdCli, @TelAvant
CONTINUE
END
-- scrutation de la valeur du téléphone
SET @i = 1
SET @j = 0
SET @TelApres = ''
-- boucle de nettoyage sur tous les caractères
WHILE @i <= LEN(@TelAvant)
BEGIN
-- reprise du caractère d'ordre i
SET @car = SUBSTRING(@TelAvant,@i,1)
-- on ne traite que les caractères de 0 à 9
IF @car = '0' or @car = '1' or @Car = '2' or @Car = '3'
or @car = '4' or @car = '5' or @Car = '6' or @Car = '7'
or @car = '8' or @car = '9'
BEGIN
SET @TelApres = @TelApres + @Car
SET @j = @j + 1
END
SET @i =@i + 1
END
-- si vide reboucle immédiatement
IF @TelApres = ''
BEGIN
FETCH CurIns INTO @IdCli, @TelAvant
CONTINUE
END
-- découpage par tranche de 2 nombres
SET @TelAvant = @TelApres
SET @i = 1
SET @TelApres = ''
-- boucle de découpage
WHILE @i <= LEN(@TelAvant)
BEGIN
SET @car = SUBSTRING(@TelAvant,@i,1)
SET @TelApres = @TelApres + @Car
IF @i % 2 = 0
SET @TelApres = @TelApres + '-'
SET @i =@i + 1
END
-- petit effet de bord si @TelApres se termine par un nombre pair,
-- alors tiret en trop !
IF @j % 2 = 0 -- au pasage % est la fonction MODULO dans SQL Server
SET @TelApres = SUBSTRING(@TelApres, 1, LEN(@TelApres)-1)
-- mise à jour si différence
IF @TelAvant <> @TelApres
UPDATE CLIENT
RETURN
CORRECTION
CREATE TRIGGER E_DEL_CLI ON T_CLIENT
FOR DELETE
AS
5- - la gestion d'un lien d'héritage suppose souvent une exclusion mutuelle entre les fils
nous allons voir comment gérer ce cas de figure. Partons d'une table T_VEHICULE dont la
spécialisation provoque deux tables : T_AVION et T_BATEAU. Un véhicule peut être un
avion ou bien un bateau mais pas les deux. Une valeur de clef présente dans
T_VEHICULE peut donc se retrouver soit dans T_BATEAU soit dans T_AVION mais on doit
éviter qu'elle se retrouve dans les deux tables.
CORRECTION
Mais cet exemple est incomplet car il faudrait créer ce même type de trigger dans la
table T_BATEAU pour vérifier la présence de la clef dans la table père et vérifier son
absence dans la table sœur. De même qu'il serait souhaitable de gérer une suppression
en cascade pour le père et éventuellement une modification de la valeur de la clef en
cascade ! Bref, à vous de jouer...
NOT EXISTS(SELECT *
FROM T_MOT MOT
JOIN T_MOT_NOIR MNR
ON MOT.MOT_MOT = MNR.MNR_MOT)
Soit toujours évaluée à vrai !
CORRECTION
On peut bien entendu tester un tel trigger avec le jeu d'essai suivant :
7-- dans une relation d'héritage, comment insérer dans une table fille alors que
l'insertion dans la table mère est un pré requis ?
Par exemple, nous avons une table des personnes, une table des clients et une table des
employés. Ces tables sont construites de la sorte :
CORRECTION
CONTRAINTES ET TRIGGERS
1. CONTRAINTES
1.1 Rappels
Les contraintes d’intégrité permettent à l’utilisateur de définir des règles que doivent
respecter lesdonnées de la base. La plupart d’entre elles sont définies lors de la création des
tables (CREATETABLE) .
contrainte de domaine (valeur possible d’un attribut, éventuellement à l’aide d’un valeur par
défaut), contrainte de clé (PRIMARY KEY et UNIQUE),
1. Exercices
La base de données d’une entreprise contient entre autres les relations suivantes :
Les attributs « id_ » sont les clés primaires des relations correspondantes.
1.2.1 Ecrire les commandes de création des trois tables en SQL sachant que :
♦ Les identificateurs sont des entiers de petite taille.
♦ Les noms sont tous des chaînes de 20 caractères
♦ La fonction d’un employé est une chaîne de 7 caractères, une ville une chaîne de 9.
♦ Salaire et prime sont en euro et centime d’euro, aucun salaire ne dépassant 40 000 euros.
1.2.3 Reprendre la création du schéma en SQL afin d’intégrer les contrainte de la question
précédente.
1.2.4 Comment modifier le schéma si, au bout d’un an d’utilisation de la base, on décide
qu’il ne
2. TRIGGERS
Exercices
1 Ecrire un trigger INSTED OF qui évite qu’un salaire ne puisse diminuer.
2 Idem avec un trigger AFTER.
3 Ecrire un trigger qui empêche qu’on supprime plus de 50 n-uplets à la fois dans la relation
EMPLOYE
4 Ecrire deux triggers AFTER implantant la contrainte d’intégrité référentielle liée au projet
D’un employé (contrainte n°9 de la question 1.2.2.) :
1.2. Exercices
On considère une base de données concernant les enseignements et les étudiants d’une
Université. Elle comprend, notamment, les relations :
1.2.1 Créer les tables TD et INSCRIPTION, avec les contraintes d’intégrité suivantes :
- contraintes de clés (clé primaire et autres clés candidates) ;
- contrainte référentielle ;
- contrainte de domaine (un TD a lieu un jour de semaine, allant du lundi au samedi).
1.2.2 Insérer dans la table TD :
- un n-uplets (t1) correspondant à un TD d’un certain module (par exemple, BD de Licence) .
- puis, en prévision de l’exercice 2.2.2, deux n-uplets (t2, t3) correspondant tous deux au
même module (par exemple, ALGO de Licence), ce module étant différent du module de t1 ;
t2 et t1 auront lieu à des moments différents, et pourront donc être choisis par un même
étudiant ; par contre, t3 et t1 se passeront au même moment.
1.2.3 Tenter d’insérer de nouveaux n-uplets contredisant les règles d'intégrité de la table TD.
1.2.4 Insérer un n-uplets dans la table INSCRIPTION, puis tenter de faire des insertions ou
des modifications contraires aux règles d’intégrité de cette seconde table.
48 Proposé par :A BENDAOUD
2. TRIGGERS
2.1. Rappels
2.2. Exercices
2.2.1 Créer un trigger qui assure que les valeurs des attributs DIPLOME et MATIERE,
entrées dans la table INSCRIPTION, soient en majuscules, quelle que soit la casse utilisée
dans les instructions d’insertion ou de mise à jour.
2.2.2 (facultatif)
Pour empêcher un étudiant de s’inscrire à des TD incompatibles (i.e. ayant lieu en même
temps), on introduit une nouvelle contrainte d’intégrité, dans la base : un étudiant ne peut pas
avoir deux inscriptions qui lui imposent d’être, au même moment, à deux endroits différents.
Ecrire un trigger qui assure cette contrainte, de la façon suivante :
- en préambule à chaque inscription, le trigger inscrit le numéro de l’étudiant, avec le jour,
l’heure et la salle du TD qu’il a choisi, dans une table supplémentaire créée au préalable avec
1. ces quatre colonnes
2. une contrainte d’intégrité qui assure l’unicité du triplet (N°ETUDIANT, JOUR, HEURE) ;
- si l’étudiant avait déjà pris une inscription correspondant au même jour et à la même heure,
la contrainte de table précédente provoque le rejet du nouveau quadruplet (N°ETUDIANT,
JOUR, HEURE, SALLE), le trigger est arrêté sur erreur, et l’instruction d’insertion d’un
nouvel élément dans la table INSCRIPTION est, par suite, arrêtée sur erreur.
Les mises à jour sont enregistrées en mémoires dans des tables logiques : inserted,
deleted ou updated selon l'instruction sql utilisée INSERT, DELETE ou UPDATE.
Insert : les nouvelles lignes ajoutées le sont dans la table d'origine et dans la table
inserted de la table origine.
Table inserted :
Delete : suppression des lignes dans la table origine et ajout des lignes supprimées dans
la table deleted
Table Deleted
Update : les lignes d'origine (sans modif) sont dans la table Deleted, les lignes modifiées
sont dans Inserted et dans la table d'origine.
Table Deleted
Table Inserted :
Dans un premier temps, l'utilisateur définit les différents comptes à gérer en déclarant
pour chacun le numéro de compte, le nom de la banque, ...
L'utilisateur saisit ensuite chacune des opérations réalisées sur l'un de ces comptes. Une
opération correspond à un débit (paiement par chèque de la facture de téléphone, retrait
d'espèces à l'aide d'une carte bancaire, ...) ou à un crédit (dépôt à la banque de chèques
reçus par exemple).
Chaque fin de mois, l'utilisateur reçoit un "relevé de compte" (un par compte bancaire).
Il effectue alors le rapprochement entre les opérations qu'il a saisies et celles constatées
par la banque :
- Ajout des opérations non saisies apparaissant sur le relevé (réception d'un virement
correspondant au salaire mensuel par exemple). Ces opérations sont automatiquement
pointées puisqu'elles ont été constatées par la banque.
Les opérations permettent de calculer le solde d'un compte, différence entre la somme des
- Le solde réel qui prend en considération toutes les opérations saisies par l'utilisateur, qu'elles aient
été constatées ou non par la banque.
- Le solde en banque qui ne prend en considération que les opérations constatées par la banque,
c'est-à-dire ayant fait l'objet d'un "pointage" à partir d'un relevé.
L'application est développée autour d'un SGBDR. Au niveau physique, on trouve notamment deux
tables :
Le calcul des soldes des comptes conduit à additionner un grand nombre d'opérations, et ce depuis la
mise en service de l'application. Pour éviter ces calculs, il a été décidé de mémoriser les soldes réel
et "en banque" dans la table COMPTE.
Dès lors se pose le problème de la cohérence entre les opérations et le solde des comptes. La
solution adoptée est le recours à un ensemble de procédures stockées et de déclencheurs (triggers)
Remarques :
- Osens est un caractère mémorisant la nature de l'opération ('d' pour débit, opération diminuant le
solde du compte ; 'c' pour crédit, opération augmentant le solde du compte).
- Oreleve contient le numéro du relevé (Rid) ayant permis de pointer l'opération. Cet attribut
contient la valeur NULL si l'opération n'a pas encore été pointée.
parameters
variables
begin
// liste d'instructions
end
variables
begin
// liste d'instructions
end
Le langage permet l'utilisation de tous les types de données courants pour la déclaration des
paramètres et des variables. Les instructions "classiques" sont présentes : affectation, conditionnelle,
boucle, appel de procédure, ...
Le langage de définition des procédures stockées supporte l'utilisation de requêtes SQL selon la
norme d'intégration de SQL dans un langage hôte (variables hôtes notamment).
Lors de l'écriture d'un trigger, il est possible d'accéder aux valeurs des attributs du
Travail à Réaliser
Correction
CORRECTION
Question 1 :
le schéma entité-association
PARAMETERS
@idCompte : entier
@sens : caractère
@montant : réel
begin
where Cid=@idCompte
else
where Cid=@idCompte
endif
end
PARAMETERS
@idCompte entier
@sens : caractère
@montant : réel
begin
if (@sens='c') then
else
endif
end
VARIABLES
@sens : caractère
begin
endif
end
VARIABLES
@sens : caractère
begin
endif
endif
end
VARIABLES
@sens : caractère
begin
endif
end
Question 3 :
Dans le cas d'une utilisation de la base de données dans une architecture client/serveur
(ce qui est assez improbable dans le contexte décrit), la solution des procédures stockées
permet également de minimiser le trafic sur le réseau et d'optimiser les temps
d'exécution.
EXERCICE
Ce petit exemple permet de voir le fonctionnement d'un trigger sur un
insert dans la table invent.
Ce trigger se déclenche lorsque l'on insert un enregistrement dans la table
invent. Il décrémente ainsi le stock de l'article si celui-ci est suivi en stock.
On retrouve cette information dans la table article grâce au champ
"ART_suivi". si ART_suivi = 0 pas de suivi de stock. Si ART_suivi = 1 =>
suivi de stock donc décrémentation du stock de cette article.
CORRECTION
SOURCE
EXERCICE
Si je supprime une ligne de la table Tcivilites et que j'ai une reference qui
pointe sur la table
Tpersonnes je vais bien sur avoir un message d'erreur du sgdbr !
Pour remedier a cela, utilisez le on delete cascade qui est bien pratique !
Donc si je supprime une ligne de la table Tcivilites et que je retrouve
sa reference dans la table Tpersonnes il me supprimera toutes les lignes
correspondantes !
CORRECTION
SOURCE
EXERCICES
La base de données "uniPubs" est une traduction en français de la base Pubs fournie avec
SQL Server.
En voici le schéma relationnel :
Exercice 2
Ecrire un trigger qui affiche l'ancien n° de tél ainsi que le nouveau lorsqu'un update
de la colonne <tel> est effectué sur un tuple de Auteur.
Lorsqu'une table est mise à jour (clause UPDATE …) deux tables virtuelles sont
créées : une table <Deleted> contenant les valeurs avant la mise à jour, et une table
<Inserted> contenant les valeurs après la mise à jour.
Exercice 3
Exercice 5 :
Les contraintes de domaine déclaratives (constraint check) ne permettent pas de se
référer à d'autres colonnes que celles pour lesquelles la contrainte a été définie.
Une règle de l'entreprise UniPubs est que pour une catégorie d'emploi (idEmploi)
donnée, le niveau d'emploi (sur lequel est basé le salaire) doit être compris entre un
minimum (nivMin) et un maximum (nivMax). Ce niveau d'emploi est donné par
posEmploi.
Créer un trigger for insert, update qui fait le contrôle de validité lorsque le niveau
d'emploi (posEmploi) d'un employé est modifié ou inséré. S'il n'est pas compris entre
les valeurs limites pour la catégorie, la transaction devra être annulée (rollback tran).
Exercice 6 :
La Direction souhaite gèrer l'historique des emplois exercés successivement par les
employés (actuellement impossible car un employe n'a qu'un idEmploi).