web-dev-qa-db-fra.com

Déclencher pour se déclencher uniquement si une condition est remplie dans SQL Server

J'espère que c'est une question assez simple pour toutes les personnes SQL là-bas ...

Nous avons une table qui contient les données de configuration du système, et elle est liée à une table d'historique via des déclencheurs afin que nous puissions suivre qui a changé quoi et quand.

J'ai une exigence pour ajouter une autre valeur à cette table, mais c'est celle qui changera fréquemment du code, et a une exigence que nous ne suivons pas son historique (nous ne voulons pas obstruer la table avec plusieurs milliers de mises à jour par jour.

À l'heure actuelle, notre déclencheur est un peu comme ça ...

CREATE TRIGGER 
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON
      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      Attribute,
      ParameterValue,
      ParameterDescription,
      ChangeDate
    FROM Inserted AS I
END

J'aimerais pouvoir ajouter de la logique pour l'empêcher de créer l'enregistrement si une valeur de colonne d'attribut est préfixée avec une chaîne spécifique (par exemple, "NoHist_")

Étant donné que je n'ai pratiquement aucune expérience de travail avec les déclencheurs, je me demandais comment il serait préférable de l'implémenter ... J'ai essayé une clause where comme la suivante

where I.Attribute NOT LIKE 'NoHist_%'

mais cela ne semble pas fonctionner. La valeur est toujours copiée dans la table d'historique.

Toute aide que vous pourriez offrir serait appréciée.


OK - comme prédit par Cade Roux, cela échoue de façon spectaculaire sur plusieurs mises à jour. Je vais devoir adopter une nouvelle approche à ce sujet. Quelqu'un a-t-il d'autres suggestions, s'il vous plaît?


Les gars - Veuillez me renseigner ici ... Pourquoi LEFT () serait-il préférable à LIKE dans ce scénario? Je sais que j'ai accepté la réponse, mais j'aimerais savoir pour ma propre éducation.

26
ZombieSheep

Étant donné qu'une clause WHERE n'a pas fonctionné, cela peut:

CREATE TRIGGER 
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON

      If (SELECT Attribute FROM INSERTED) LIKE 'NoHist_%'
      Begin
          Return
      End

      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      Attribute,
      ParameterValue,
      ParameterDescription,
      ChangeDate
    FROM Inserted AS I
END
40
Joel Coehoorn

Que dis-tu de ça?

CREATE TRIGGER 
[dbo].[SystemParameterInsertUpdate]
ON 
[dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
BEGIN
SET NOCOUNT ON
  IF (LEFT((SELECT Attribute FROM INSERTED), 7) <> 'NoHist_') 
  BEGIN
      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      Attribute,
      ParameterValue,
      ParameterDescription,
      ChangeDate
   FROM Inserted AS I
END
END
7
Matty

Votre clause where aurait dû fonctionner. Je ne comprends pas pourquoi cela n'a pas été le cas. Permettez-moi de vous montrer comment j'aurais résolu le problème de la clause where, car cela pourrait vous aider à l'avenir.

Lorsque je crée des déclencheurs, je commence à la fenêtre de requête en créant une table temporaire appelée #insérée (et ou # supprimée) avec toutes les colonnes de la table. Ensuite, je le popultae avec des valeurs typiques (toujours plusieurs enregistrements et j'essaie de frapper les cas de test dans les valeurs)

Ensuite, j'écris ma logique de déclencheurs et je peux tester sans qu'il soit réellement dans un déclencheur. Dans un cas comme votre clause where ne faisant pas ce qui était attendu, je pourrais facilement tester en commentant l'insertion pour voir ce que la sélection renvoyait. Je pourrais alors probablement facilement voir quel était le problème. Je vous assure que là où les clauses fonctionnent dans les déclencheurs si elles sont écrites correctement.

Une fois que je sais que le code fonctionne correctement pour tous les cas, je remplace globalement #insertion par inséré et ajoute le code de déclenchement de création autour de lui et le tour est joué, un déclencheur testé.

Comme je l'ai dit dans un commentaire, je crains que la solution que vous avez choisie ne fonctionne pas correctement dans une insertion ou une mise à jour d'enregistrements multiples. Les déclencheurs doivent toujours être écrits pour tenir compte de cela, car vous ne pouvez pas prédire si et quand ils se produiront (et ils se produisent finalement à peu près à chaque table.)

5
HLGEM

Le _ le caractère est également un caractère générique, BTW, mais je ne sais pas pourquoi cela ne fonctionnait pas pour vous:

CREATE TRIGGER 
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON
      INSERT INTO SystemParameterHistory 
      (
        Attribute,
        ParameterValue,
        ParameterDescription,
        ChangeDate
      )
    SELECT
      I.Attribute,
      I.ParameterValue,
      I.ParameterDescription,
      I.ChangeDate
    FROM Inserted AS I
    WHERE I.Attribute NOT LIKE 'NoHist[_]%'
END
5
Cade Roux
CREATE TRIGGER
    [dbo].[SystemParameterInsertUpdate]
ON 
    [dbo].[SystemParameter]
FOR INSERT, UPDATE 
AS
  BEGIN
    SET NOCOUNT ON 

    DECLARE @StartRow int
    DECLARE @EndRow int
    DECLARE @CurrentRow int

    SET @StartRow = 1
    SET @EndRow = (SELECT count(*) FROM inserted)
    SET @CurrentRow = @StartRow

    WHILE @CurrentRow <= @EndRow BEGIN

        IF (SELECT Attribute FROM (SELECT ROW_NUMBER() OVER (ORDER BY Attribute ASC) AS 'RowNum', Attribute FROM inserted) AS INS WHERE RowNum = @CurrentRow) LIKE 'NoHist_%' BEGIN

            INSERT INTO SystemParameterHistory(
                Attribute,
                ParameterValue,
                ParameterDescription,
                ChangeDate)
            SELECT
                I.Attribute,
                I.ParameterValue,
                I.ParameterDescription,
                I.ChangeDate
            FROM
                (SELECT Attribute, ParameterValue, ParameterDescription, ChangeDate FROM (
                                                                                            SELECT ROW_NUMBER() OVER (ORDER BY Attribute ASC) AS 'RowNum', * 
                                                                                            FROM inserted)
                                                                                    AS I 
            WHERE RowNum = @CurrentRow

        END --END IF

    SET @CurrentRow = @CurrentRow + 1

    END --END WHILE
END --END TRIGGER