web-dev-qa-db-fra.com

SQL Server: déclencheur d'insertion de mise à jour et de suppression intercepté lorsqu'aucune donnée n'a été modifiée?

J'ai ajouté une table simple à une base de données appelée: aaa_log avec des colonnes: (id, name, op))

CREATE TABLE aaa_log (
   [id] [int] IDENTITY(1,1) PRIMARY KEY NOT NULL,
   [name] [varchar](50) NOT NULL,
   [op] [varchar](50) NULL)

id colonne utilisée juste pour conserver l'ordre.

J'ai ajouté un déclencheur (for insert, update, delete) à toutes les autres tables d'une base de données à l'aide du script suivant:

declare @cmd varchar(max)
declare trigger_create cursor for
select 'Create trigger ['+TABLE_SCHEMA+'].[xxtr_'+TABLE_NAME+'_auto]
  on ['+TABLE_SCHEMA+'].['+TABLE_NAME+'] fro insert,update,delete as
  BEGIN
   declare @op varchar(20)
   if exists(SELECT * from inserted)  and exists(SELECT * from deleted)
   begin
     set @op = ''update''
   end
   if exists(SELECT * from inserted)  and not exists(SELECT * from deleted)
   begin
     set @op = ''insert''
   end
   if not exists(SELECT * from inserted)  and exists(SELECT * from deleted)
   begin
     set @op = ''delete''
   end
   insert into aaa_log([name],[op]) values('+TABLE_SCHEMA+'.'+TABLE_NAME+', @op)
  END
'
from information_schema.tables
where table_type='BASE TABLE' AND table_name <> 'aaa_log'

open trigger_create
fetch next from trigger_create into @sql
while @@FETCH_STATUS =0
BEGIN 
  exec(@sql)
  fetch next from trigger_create into @sql
END
close trigger_create
deallocate trigger_create

Personne d'autre ne met à jour le aaa_log table, juste ces déclencheurs, mais quand je vérifie le aaa_log table Je vois quelques lignes où op est NULL.

La seule option à laquelle je peux penser est qu'inséré et mis à jour est nul, alors comment le déclencheur a-t-il été activé?

Une explication?

6
SHR

Vous comptez sur la présence de lignes dans inserted ou deleted (ou les deux). Que se passe-t-il lorsqu'aucune ligne n'est affectée? La détente se déclenche toujours.

CREATE TABLE dbo.floob(a int);
INSERT dbo.floob(a) VALUES(1);
GO

CREATE TRIGGER dbo.TRfloob
ON dbo.floob
FOR INSERT, UPDATE, DELETE
AS
BEGIN
  IF    NOT EXISTS (SELECT 1 FROM inserted) 
    AND NOT EXISTS (SELECT 1 FROM deleted)
  BEGIN
    PRINT 'Strange, unknown operation!';
  END
END
GO

UPDATE dbo.floob SET a = 2 WHERE a = 2;
GO

Pour éviter ce genre de chose, les gens démarrent généralement leur déclencheur avec quelque chose comme:

IF     NOT EXISTS (SELECT 1 FROM inserted) 
   AND NOT EXISTS (SELECT 1 FROM deleted)
BEGIN
  RETURN;
END

Vérification @@ROWCOUNT est populaire aussi, mais je le trouve beaucoup plus fragile.

8
Aaron Bertrand

Question: Devriez-vous prendre des mesures contre la base de données si aucune modification n'est apportée? Cela semble ralentir inutilement votre application et ce n'est pas la meilleure pratique.

Je dirais ici qu'une meilleure solution serait de supprimer les transactions de base de données inutiles, si possible.

Si ce déclencheur est destiné à auditer de quelque manière que ce soit (ce à quoi il ressemble), la réponse de @Aaron Bertrand n'enregistrera aucune mise à jour de la table d'audit.

2
Devon Di Vito