Quel est le moyen le plus portable de vérifier si un déclencheur existe dans SQL Server?
-
10-07-2019 - |
Question
Je recherche la méthode la plus portable pour vérifier l'existence d'un déclencheur dans MS SQL Server. Il doit fonctionner au moins sur SQL Server 2000, 2005 et de préférence 2008.
Les informations ne semblent pas figurer dans INFORMATION_SCHEMA, mais si elles s'y trouvent quelque part, je préférerais les utiliser à partir de là.
Je connais cette méthode:
if exists (
select * from dbo.sysobjects
where name = 'MyTrigger'
and OBJECTPROPERTY(id, 'IsTrigger') = 1
)
begin
end
Mais je ne suis pas sûr que cela fonctionne avec toutes les versions de SQL Server.
La solution
Ceci fonctionne sur SQL Server 2000 et supérieur
IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') = 1
BEGIN
...
END
Notez que la conversation naïve ne fonctionne pas de manière fiable:
-- This doesn't work for checking for absense
IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') <> 1
BEGIN
...
END
... parce que si l'objet n'existe pas du tout, OBJECTPROPERTY
renvoie NULL
, et <> 1
n'est (bien sûr) pas COALESCE
(ni rien d'autre).
Sous SQL Server 2005 ou version ultérieure, vous pouvez utiliser 0
cette option, mais si vous devez prendre en charge SQL Server 2000, vous devez structurer votre instruction de manière à prendre en charge les trois valeurs de retour possibles: <= > (l'objet n'existe pas du tout), 1
(il existe mais ce n'est pas un déclencheur) ou <=> (c'est un déclencheur).
Autres conseils
Il existe également le & "sys.triggers &" préféré; vue catalogue:
select * from sys.triggers where name = 'MyTrigger'
ou appelez le proc sp_Helptrigger stocké:
exec sp_helptrigger 'MyTableName'
Mais à part ça, je suppose que c'est à peu près tout: -)
Marc
Mise à jour (pour Jakub Januszkiewicz):
Si vous devez inclure les informations de schéma, vous pouvez également procéder de la manière suivante:
SELECT
(list of columns)
FROM sys.triggers tr
INNER JOIN sys.tables t ON tr.parent_id = t.object_id
WHERE t.schema_id = SCHEMA_ID('dbo') -- or whatever you need
En supposant qu'il s'agisse d'un déclencheur DML:
IF OBJECT_ID('your_trigger', 'TR') IS NOT NULL
BEGIN
PRINT 'Trigger exists'
END
ELSE
BEGIN
PRINT 'Trigger does not exist'
END
Pour les autres types d'objets (tables, vues, clés, etc.), voir: http : //msdn.microsoft.com/en-us/library/ms190324.aspx sous "type".
Testé et ne fonctionne pas sur SQL Server 2000:
select * from sys.triggers where name = 'MyTrigger'
Testé et fonctionne correctement sous SQL Server 2000 et SQL Server 2005:
select * from dbo.sysobjects
where name = 'MyTrigger' and OBJECTPROPERTY(id, 'IsTrigger')
En plus de l'excellente réponse de marc_s:
si le contrôle d'existence est prévu avant de supprimer ou de modifier le déclencheur d'une manière ou d'une autre, utilisez un bloc direct TSQL try/Catch
, comme moyen le plus rapide.
Par exemple:
BEGIN TRY
DROP TRIGGER MyTableAfterUpdate;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS erno WHERE erno = 3701; -- may differ in SQL Server < 2005
END CATCH;
Le message d'erreur sera
Cannot drop the trigger 'MyTableAfterUpdate', because it does not exist or you do not have permission.
Il suffit ensuite de vérifier si le résultat exécuté renvoie des lignes ou non, ce qui est facile à utiliser dans SQL direct ainsi que dans les API de programmation (C #, ...).
Les noms de déclencheurs sont-ils forcés d'être uniques dans SQL Server?
Comme les déclencheurs sont par définition appliqués à une table spécifique, ne serait-il pas plus efficace de limiter la recherche à la seule table en question?
Nous avons une base de données contenant plus de 30 000 tables, qui ont toutes au moins un déclencheur et peuvent en avoir plusieurs (mauvaise conception de base de données - très probablement, mais cela avait du sens il y a des années et n'a pas bien évolué)
j'utilise
SELECT * FROM sys.triggers
WHERE [parent_id] = OBJECT_ID(@tableName)
AND [name] = @triggerName
Je voudrais utiliser cette syntaxe pour vérifier et supprimer le déclencheur
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[SCHEMA_NAME].[TRIGGER_NAME]') AND type in (N'TR'))
DROP TRIGGER [SCHEMA_NAME].[TRIGGER_NAME]
Si vous essayez de trouver un déclencheur DDL avec périmètre d'application sur SQL Server 2014, vous devriez essayer sys.server_triggers.
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = 'your trigger name')
BEGIN
{do whatever you want here}
END
Si je vous dis quelque chose d’erreur, merci de me le faire savoir.
Modifier: Je n'ai pas vérifié cette dm sur d'autres versions de SQL Server.
Généré par SQL Server Management Studio :
IF EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'[dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]'))
DROP TRIGGER [dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]
GO
CREATE TRIGGER [dbo].[RolesYAccesos2016_UsuariosCRM_trgAfterInsert]
ON [PortalMediadores].[dbo].[RolesYAccesos2016.UsuariosCRM]
FOR INSERT
AS
...
Pour select @@version
Microsoft SQL Server 2008 R2 (RTM) - 10.50.1797.0 (X64) 1 juin 2011 15:43:18 Droits d'auteur (c) Microsoft Corporation Enterprise Edition (64 bits) sous Windows NT 6.1 (version 7601: Service Pack 1) (Hyperviseur)