Je travaille sur SQL Server 2008 R2.
J'ai une table avantage qui a un déclencheur AFTER INSERT, UPDATE nommé tiu_benefit.
Je veux écrire une instruction UPDATE pour que cette table mette à jour 1 ligne, mais je ne veux pas que son déclencheur se déclenche. Je sais que je peux désactiver le déclencheur avant UPDATE, puis activer le déclencheur après UPDATE:
DISABLE TRIGGER tiu_benefit ON benefit;
GO
UPDATE benefit SET editor = 'srh' where benefit_id = 9876
GO
ENABLE TRIGGER tiu_benefit ON benefit;
GO
Mais ce déclencheur de désactivation et d'activation affectera tous les utilisateurs connectés actuellement. Il est donc possible qu'un autre utilisateur exécute une MISE À JOUR/INSÉRER alors que le déclencheur est désactivé par mon script, ce qui n'est pas bon. C'est pourquoi je veux seulement désactiver et activer le déclencheur pour ma session actuelle. C'est possible? Si oui, dites comment.
Merci
J'ai fait quelques tests à ce sujet et je pense que vous iriez bien si vous exécutez votre processus en une seule transaction.
BEGIN TRANSACTION
GO
DISABLE TRIGGER tiu_benefit ON benefit;
GO
UPDATE benefit
SET editor = 'srh'
WHERE benefit_id = 9876
GO
ENABLE TRIGGER tiu_benefit ON benefit;
GO
--Decide to commit or rollback
--commit
--rollback
Lors de mes tests, j'ai uniquement mis en évidence et exécuté le BEGIN TRANSACTION
et le DISABLE TRIGGER
première. J'ai ensuite ouvert une nouvelle (seconde) fenêtre de requête et essayé d'exécuter diverses instructions DML (SELECT
, INSERT
, UPDATE
DELETE
) sur la table de base . Toutes les tentatives d'accès à la table de base dans la deuxième fenêtre de requête ont attendu les verrous détenus par la fenêtre avec la transaction explicite. Une fois que j'ai validé (ou annulé) ma transaction explicite, la deuxième fenêtre a pu accéder à la table.
Pour résoudre votre problème, nous devons adopter une approche programmatique du problème. Il y a deux itinéraires que vous pouvez emprunter ici. La raison pour laquelle ces approches sont nécessaires est que vous ne pouvez pas désactiver un déclencheur pour une instruction particulière, il ne peut être désactivé que pour l'intégralité du tableau.
Option 1: Context_Info ()
Samuel Vanga sur MS SQL Tips avait un excellent exemple:
USE AdventureWorks;
GO
-- creating the table in AdventureWorks database
IF OBJECT_ID('dbo.Table1') IS NOT NULL
DROP TABLE dbo.Table1
GO
CREATE TABLE dbo.Table1(ID INT)
GO
-- Creating a trigger
CREATE TRIGGER TR_Test ON dbo.Table1 FOR INSERT,UPDATE,DELETE
AS
DECLARE @Cinfo VARBINARY(128)
SELECT @Cinfo = Context_Info()
IF @Cinfo = 0x55555
RETURN
PRINT 'Trigger Executed'
-- Actual code goes here
-- For simplicity, I did not include any code
GO
Maintenant, quand Samuel ne veut pas que le déclencheur s'exécute, ils utilisent ceci:
SET Context_Info 0x55555
INSERT dbo.Table1 VALUES(100)
Context_Info
utilise les vues système suivantes pour récupérer des informations concernant la session en cours:
sys.dm_exec_requests
sys.dm_exec_sessions
sys.sysprocesses
L'idéologie ici est que la chaîne binaire que vous définissez n'est exposée qu'à la session en cours, donc lorsque le déclencheur s'exécute pendant votre session, il verra la portée et le paramètre de variable du Context_info
fonction et il passera à la partie d'échappement du déclencheur à la place.
Option 2: Tableau des températures
Itzik Ben-Gan a une excellente solution dans son livre "Inside Microsoft SQL Server 2008 Programmation T-SQL: Programmation T-SQL" qui est également dans son dernier livre - Requête T-SQL . Le principal problème avec cela sur le context_info
est la surcharge mineure de TempDB.
Pour gâcher la surprise mais ne pas gâcher l'intrigue des livres (j'ai senti qu'ils valent la peine d'être achetés et lus), vous allez modifier votre déclencheur.
Votre déclencheur doit effectuer une vérification pour une table temporaire. Si la table temporaire existe, le déclencheur doit savoir se terminer et ne pas effectuer les actions.
Dans l'instruction de mise à jour que vous souhaitez effectuer, créez d'abord la table temporaire. Il apparaîtra dans la même transaction que le déclencheur et entraînera le déclencheur à ignorer votre instruction.
Exemple de déclencheur:
CREATE TRIGGER TRIGGERNAME ON TABLENAME for INSERT AS
IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
GO
Exemple d'instruction de début lorsque vous ne voulez pas que le déclencheur s'exécute:
CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);
Mettre tout à fait pour votre exemple:
ALTER TRIGGER tiu_benefit ON benefit FOR
...
AS
...
IF OBJECT_ID('tempdb..#FAKETEMPTABLE') IS NOT NULL RETURN;
--... rest of code here
GO
CREATE TABLE #FAKETEMPTABLE(col1 SMALLINT);
UPDATE benefit SET editor = 'srh' where benefit_id = 9876;
GO
J'utiliserais soit CONTEXT_INFO
Soit le nouveau SESSION_CONTEXT
. Les deux sont des valeurs basées sur la session.
CONTEXT_INFO
Est une seule valeur VARBINARY(128)
. Celui-ci est disponible depuis au moins SQL Server 2000. CONTEXT_INFO
Est visible par toute personne disposant de VIEW SERVER STATE
Car il s'agit d'un champ renvoyé par le DMV sys.dm_exec_sessions
. J'ai déjà utilisé celui-ci et il fonctionne plutôt bien.
Définir via SET CONTEXT_INFO
Obtenez via CONTEXT_INFO () ou sys.dm_exec_sessions
Selon le type de valeur que vous stockez dans CONTEXT_INFO
, Certaines nuances doivent être prises en compte. Je couvre cela dans le blog suivant:
Pourquoi CONTEXT_INFO () ne renvoie-t-il pas la valeur exacte définie par SET CONTEXT_INFO?
Session_context est une paire clé/valeur de valeurs SQL_VARIANT
. Cela a été introduit dans SQL Server 2016. La séparation des valeurs à des fins différentes est assez agréable. Session_context n'est visible que par la session en cours.
Définissez cette valeur via sp_set_session_context
Obtenez cette valeur via SESSION_CONTEXT
Une chose à considérer concernant l'option de table temporaire locale et même l'option de désactivation/activation du déclencheur: les deux nécessitent une certaine quantité de verrouillage et d'activité du journal de transfert. Ces deux options augmentent le potentiel de contention, même minime. Les deux options "contextuelles" doivent être plus légères/mémoire uniquement.