Partage
  • Partager sur Facebook
  • Partager sur Twitter

Transact SQL : trigger

vérification de la valeur d'un champ

    18 mai 2018 à 12:19:29

    Salut tout le monde!

    J'ai une table qui stocke tous les articles qui sont écrits par mes auteurs. Le nom des champs est assez explicite pour que je ne passe pas trop de temps à expliquer à quoi ils servent Mise à part 'affichage' peut-être, qui est le champ qui indique si l'article en question est publié ou non.

    CREATE TABLE auteur(
        id_auteur int IDENTITY(1,1) PRIMARY KEY,
        nom  varchar(32) NOT NULL,
        prenom VARCHAR(25)
    )
    
    CREATE TABLE 'article' (
        'id' int IDENTITY(1,1) PRIMARY KEY,
        'date' datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        'libelle' varchar(100) NOT NULL,
        'contenu' text NOT NULL,
        'affichage' bit NOT NULL DEFAULT 0,
        id_auteur INT NOT NULL REFERENCES auteur(id_auteur)
    )

    Le problème que je rencontre tient à une contrainte de fonctionnement : "Un et UN SEUL article doit être publié à la fois".

    Donc quand j'enregistre un nouvel article je voudrais faire une vérification à l'aide d'un trigger. Si la valeur de 'affichage' est égale à 1, alors je lance un update sur ma table pour passer le champ 'affichage' de tous mes articles à 0.

    Seulement voilà, je n'arrive pas à effectuer la vérification de la valeur de mon champ.

    CREATE TRIGGER show_only_one_news_insert 
       ON  article 
      FOR INSERT, UPDATE
    AS 
    BEGIN
    	IF (UPDATE(affichage)) 
    		BEGIN
    		DECLARE @show int
    		SET @show = 1
    		IF (inserted.affichage == @show)
    			UPDATE article SET affichage = 0
    		END
    	END
    END
    GO


    Le "IF (INSERTED.affichage == @show)" ne semble pas fonctionner. Est-ce que vous voyez pourquoi?

    Ma seconde interrogation est la suivante : Si mon trigger lance un UPDATE après l'insertion de mon nouvel article, ne risque t'il pas de passer également la valeur du champ 'affichage' de cet article à 0 ? Auquel cas mon approche n'est peut-être pas la bonne...

    Bref je veux bien un coup de pouce, parce "je tambouille dans le cafouillie" comme dirait Alizée. ;-)

    • Partager sur Facebook
    • Partager sur Twitter
      18 mai 2018 à 12:30:15

      Bonjour,

      Tu ne peux pas faire un UPDATE de la même table que celle concernée par le TRIGGER sinon c'est une boucle infinie ...

      Je te conseille plutôt d'exécuter deux requêtes : ton insert et immédiatement après ton UPDATE ...

      INSERT INTO article ( ... )
      VALUES ( ... );
      
      UPDATE article
      SET affichage = 0
      WHERE id < SCOPE_IDENTITY();
      • Partager sur Facebook
      • Partager sur Twitter
      Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
        18 mai 2018 à 12:56:39

        Merci pour ta réponse Benzouye!

        Je ne crois pas que cela forme une boucle infinie. Si pendant mon insertion mon champ 'affichage' est à 1, alors je lance un update sur ma table. Ce qui relance mon trigger une fois je te l'accorde, mais comme l'update de ma table à pour but de mettre tous les champs 'affichage' à 0, la boucle s'arrête au deuxième passage.

        Par contre je ne sais pas dans quel sens le trigger opère. S'il passe APRÈS l'insertion alors oui ça pause problème vu qu'il va également passer le champ 'affichage' de ma ligne insérée à 0. Donc du coup je n'aurai jamais d'article publié, ce qui serait ennuyant. ;')

        D'où le sens de ma deuxième question.

        • Partager sur Facebook
        • Partager sur Twitter
          18 mai 2018 à 13:16:40

          Masterbatoon a écrit:

          Je ne crois pas que cela forme une boucle infinie

          Il me semble que SQL Server n'autorise pas l'update de la même table dans un trigger et devrait te retourner une erreur ... Juste pour éviter les boucles infinies ...

          Après tu peux juste conserver l'idée du SCOPE_IDENTITY pour éviter de passer à 0 le dernier insert :

          CREATE TRIGGER show_only_one_news_insert
          ON  article
          FOR INSERT
          AS
          BEGIN
          	UPDATE article
          	SET affichage = 0
          	WHERE id < inserted.id;
          END
          GO

          Mais je trouve juste cela plus simple de le faire en deux requêtes, sans TRIGGER comme proposé plus haut ...

          -
          Edité par Benzouye 18 mai 2018 à 13:17:45

          • Partager sur Facebook
          • Partager sur Twitter
          Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
            18 mai 2018 à 15:23:53

            En effet cela me semble bien compliquer à faire en trigger, j'ai donc utilisé deux requêtes successives.

            Voic l'update utilisée:

            UPDATE article 
            SET affichage = 0 
            WHERE id < (SELECT MAX(id) FROM article)


            Je tiens tout de suite à préciser que je ne fais qu'une insertion à la fois, donc même si la technique du MAX(id) n'est pas très propre, le risque est limité dans mon cas. Je ne pouvais pas utiliser SCOPE_IDENTITY() comme tu me l'a conseillé puisque se sont 2 requêtes non liées, elles ne sont pas dans la même session. (le résultat était toujours null).

            C'est dommage car j'aimais bien le principe du trigger, mais apparemment c'est un peu compliqué en MS SQL. Personne n'a su me dire comment on vérifiait la valeur d'un champ. (pour connaitre la valeur de 'affichage' par exemple pendant mon insertion). C'est quand même étrange, ça semvble être une action simple que de tester une valeur, mais ne fait ça ne l'est pas! ;p

            Bref, ça fonctionne mais la technique n'est pas à classer dans les BEST PRACTICES.

            -
            Edité par Masterbatoon 18 mai 2018 à 15:28:58

            • Partager sur Facebook
            • Partager sur Twitter
              18 mai 2018 à 15:40:16

              Masterbatoon a écrit:

              Personne n'a su me dire comment on vérifiait la valeur d'un champ. (pour connaitre la valeur de 'affichage' par exemple pendant mon insertion).

              Bah ? inserted.affichage non ?

              Je pense que je ne comprends pas ce que tu cherches ...

              A chaque fois que l'on insère ou met à jour un article, si l'article inséré ou mis à jour a affichage = 1 alors on passe tous les autres articles à affichage = 0 ?

              CREATE TRIGGER show_only_one_news_insert
              ON  article
              FOR INSERT
              AS
              BEGIN
                  IF inserted.affichage = 1 THEN
                      UPDATE article
                      SET affichage = 0
                      WHERE id < inserted.id;
                  END IF;
              END
              GO

              -
              Edité par Benzouye 18 mai 2018 à 15:40:29

              • Partager sur Facebook
              • Partager sur Twitter
              Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL
                18 mai 2018 à 16:14:19

                Si c'est bien ce que je veux faire, mais "IF inserted.affichage = 1" ne fonctionne pas. J'ai un message "The multi-part identifier 'inserted.affichage' could not be bound".

                -
                Edité par Masterbatoon 18 mai 2018 à 16:15:30

                • Partager sur Facebook
                • Partager sur Twitter
                  18 mai 2018 à 16:51:26

                  Masterbatoon a écrit:

                  The multi-part identifier 'inserted.affichage' could not be bound

                  Je ne connais pas très bien SQL Server, mais il semble qu'il faille spécifier la pseudo-table inserted avant de l'utiliser.

                  Je pense donc que ceci devrait fonctionner :

                  CREATE TRIGGER show_only_one_news_insert
                  ON  article
                  FOR INSERT
                  AS
                  BEGIN
                      IF ( SELECT affichage FROM inserted ) = 1 THEN
                          UPDATE article a
                          SET a.affichage = 0
                          FROM inserted
                          WHERE a.id < inserted.id;
                      END IF;
                  END
                  GO
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Seul on va plus vite, ensemble on va plus loin ... A maîtriser : Conception BDD, MySQL, PHP/MySQL

                  Transact SQL : trigger

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown