Qual è il modo più portatile per verificare se esiste un trigger in SQL Server?
-
10-07-2019 - |
Domanda
Sto cercando il metodo più portatile per verificare l'esistenza di un trigger in MS SQL Server. Deve funzionare almeno su SQL Server 2000, 2005 e preferibilmente 2008.
Le informazioni non sembrano essere in INFORMATION_SCHEMA, ma se sono lì da qualche parte, preferirei usarle da lì.
Conosco questo metodo:
if exists (
select * from dbo.sysobjects
where name = 'MyTrigger'
and OBJECTPROPERTY(id, 'IsTrigger') = 1
)
begin
end
Ma non sono sicuro che funzioni su tutte le versioni di SQL Server.
Soluzione
Funziona su SQL Server 2000 e versioni successive
IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') = 1
BEGIN
...
END
Nota che il contrario ingenuo non funziona in modo affidabile:
-- This doesn't work for checking for absense
IF OBJECTPROPERTY(OBJECT_ID('{your_trigger}'), 'IsTrigger') <> 1
BEGIN
...
END
... perché se l'oggetto non esiste affatto, OBJECTPROPERTY
restituisce NULL
e <> 1
è (ovviamente) non COALESCE
(o qualsiasi altra cosa).
Su SQL Server 2005 o versioni successive, è possibile utilizzare 0
per gestirlo, ma se è necessario supportare SQL Server 2000, è necessario strutturare la propria istruzione per gestire i tre possibili valori restituiti: <= > (l'oggetto non esiste affatto), 1
(esiste ma non è un trigger) o <=> (è un trigger).
Altri suggerimenti
C'è anche il " preferito; sys.triggers " vista del catalogo:
select * from sys.triggers where name = 'MyTrigger'
o chiama il proc memorizzato sp_Helptrigger:
exec sp_helptrigger 'MyTableName'
Ma a parte questo, immagino che sia a questo proposito :-)
Marc
Aggiornamento (per Jakub Januszkiewicz):
Se devi includere le informazioni sullo schema, puoi anche fare qualcosa del genere:
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
Supponendo che sia un trigger DML:
IF OBJECT_ID('your_trigger', 'TR') IS NOT NULL
BEGIN
PRINT 'Trigger exists'
END
ELSE
BEGIN
PRINT 'Trigger does not exist'
END
Per altri tipi di oggetti (tabelle, viste, chiavi, qualunque cosa ...), vedere: http : //msdn.microsoft.com/en-us/library/ms190324.aspx in "tipo".
Testato e non funziona su SQL Server 2000:
select * from sys.triggers where name = 'MyTrigger'
Testato e funziona correttamente su SQL Server 2000 e SQL Server 2005:
select * from dbo.sysobjects
where name = 'MyTrigger' and OBJECTPROPERTY(id, 'IsTrigger')
Oltre all'ottima risposta di marc_s:
se il controllo dell'esistenza è previsto prima di rilasciare o modificare il trigger in qualche modo, utilizzare un blocco diretto TSQL try/Catch
, come mezzo più veloce.
Ad esempio:
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;
Il messaggio di errore sarà
Cannot drop the trigger 'MyTableAfterUpdate', because it does not exist or you do not have permission.
Quindi controlla semplicemente se il risultato eseguito ha restituito righe o meno, il che è facile in sql diretto e nelle API programmatiche (C #, ...).
I nomi dei trigger sono obbligati a essere univoci in SQL Server?
Poiché i trigger vengono applicati per definizione a una tabella specifica, non sarebbe più efficace limitare la ricerca solo alla tabella in questione?
Abbiamo un database con oltre 30k tabelle al suo interno che hanno almeno un trigger e potrebbero averne di più (cattiva progettazione di DB - molto probabilmente, ma aveva senso anni fa e non si ridimensionava bene)
Uso
SELECT * FROM sys.triggers
WHERE [parent_id] = OBJECT_ID(@tableName)
AND [name] = @triggerName
Userei questa sintassi per controllare e rilasciare il trigger
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]
Se stai cercando di trovare un trigger DDL con ambito server su SQL Server 2014, dovresti provare sys.server_triggers.
IF EXISTS (SELECT * FROM sys.server_triggers WHERE name = 'your trigger name')
BEGIN
{do whatever you want here}
END
Se ti ho detto qualcosa di sbagliato, per favore fatemelo sapere.
Modifica: Non ho verificato questo dm su altre versioni di SQL Server.
Generato da 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
...
Per select @@version
Microsoft SQL Server 2008 R2 (RTM) - 10.50.1797.0 (X64) 1 giugno 2011 15:43:18 Copyright (c) Microsoft Corporation Enterprise Edition (64 bit) su Windows NT 6.1 (build 7601: Service Pack 1) (Hypervisor)