IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement SQL Server Discussion :

Il ne peut en rester qu'un! [2008]


Sujet :

Développement SQL Server

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut Il ne peut en rester qu'un!
    Bonjour à toutes et à tous,

    Tout d'abord, toutes mes excuses pour la référence cinématographique lourdingue de mon titre.

    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

    Soit la table suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    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,
        'auteur' varchar(15) NOT NULL
    );
    Par contre, le champ 'affichage' reçoit un boléen qui indique si mon article doit être publié ou non. Je ne peux afficher qu'un seul article. Je dois donc vérifier à chaque insertion si le nouvel article est a publier. Si tel est le cas, je dois "dépublier" l'article en cours de diffusion.

    Donc faire une petite vérification du type:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Si (new.'article'.'affichage' == 1) {
    old.'article'.'affichage' = 0; //pour tous les articles enregistrés
    }
    Je crois savoir que c'est possible avec SQL Server, j'en suis même sûr, mais je ne sais pas du tout comment faire.
    Avez-vous une piste sur la procédure ?

    THX !

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Bonjour,
    Dans le trigger, New et Old font référence à la même ligne de la table (mais après et avant modification).
    Donc avec ton code, tu ne fais que forcer à 0 la colonne affichage de l'enregistrement courant si elle est mise à 1 lors de l'insert.

    Pour modifier les autres lignes, tu dois faire un update de la table, pour toutes les lignes dont l'Id est différent de celui de la ligne courante.

    Tatayo.

  3. #3
    Invité
    Invité(e)

  4. #4
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 768
    Points : 52 577
    Points
    52 577
    Billets dans le blog
    5
    Par défaut
    Il n'y aurait pas besoin de déclencheur si votre modèle de données était cohérent. Or il ne l'est pas.

    Il vous faut une table auteur car vous pouvez avoir des homonymes...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    CREATE TABLE auteur(
        id_auteur int IDENTITY(1,1) PRIMARY KEY,
        nom  varchar(32) NOT NULL,
        prenom VARCHAR(25)
    )
    Voatre table article référence les auteurs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    CREATE TABLE article (
        id_article 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)
    )
    Pour être sur qu 'un seul article sera publié par auteur, il suffit de faire un lien inverse des articles vers l'uateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ALTER TABLE auteur
       ADD id_article INT REFERENCES article (id_article);
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    Bonjour tout le monde!

    Merci d'avoir pris le temps de me répondre.

    @7gyY9w1ZY6ySRgPeaefZ : en effet je me penche sur les triggers pour trouver ma solution. J'étudie

    @SQLpro : "Pour être sur qu'un seul article sera publié par auteur, il suffit de faire un lien inverse des articles vers l'auteur".

    Ce n'est pas ce que je cherche à faire. Ma contrainte doit porter sur le fait qu'un seul article doit être publié, un seul article en tout, pas seulement par auteur. Par ailleurs tu as raison le modèle de données n'est pas cohérent mais je dois conjuguer avec l'existant.

    Je crois donc que je vais devoir faire deux trigger, l'un en BEFORE INSERT et l'autre en BEFORE UPDATE. Je ne sais pas encore comment les écrire mais je vais travailler là-dessus.

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    Bon... après quelques heures passées à s'arracher les cheveux voici mon avancée... J'en suis un peu au même point.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    CREATE TRIGGER monTriggerQuiNeFonctionnePas 
       ON  maBase.maTable 
      AFTER INSERT
    AS 
    BEGIN
    	IF maBase.maTable.monChamp = 1
    		BEGIN
    		UPDATE maBase.maTable SET monChamp = 0
    		END
     
    END
    GO
    La syntaxe doit pas être bonne au niveau de mon IF, SQL Server ne reconnaît jamais mon champ, peut importe comment je le nomme (monChamp, maTable.monChamp, maBase.maTable.monChamp).

    Quelqu'un a une piste siou plait ?

  7. #7
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Avec le lien fournit par 7gyY9w1ZY6ySRgPeaefZ, vous devriez au moins écrire une syntaxe correcte.

  8. #8
    Invité
    Invité(e)
    Par défaut
    maBase.maTable non ! c'est monSchéma.maTable
    Et un Update sans clause WHERE, ça ne vous choque pas ?
    Et lisez un peu à quoi servent les pseudo tables INSERTED et DELETED...

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    @7gyY9w1ZY6ySRgPeaefZ

    1 - "maBase.maTable non ! c'est monSchéma.maTable"
    Désolé pour l'erreur de vocabulaire, je ne suis pas un expert en BDD, je ne sais même pas ce qu'est un schéma.

    2 - "Et un Update sans clause WHERE, ça ne vous choque pas ?"
    Il en faut plus pour me choquer! Je pensais qu'en ne mettant pas de clause WHERE j'allais faire un UPDATE sur tous les champs... mais apparemment j'avais tord. Encore un truc que j'ai dû mal comprendre.

    3 - "Et lisez un peu à quoi servent les pseudo tables INSERTED et DELETED"
    Je vais m'y pencher de ce pas.

    Je m'aperçois que tous mes cours de BDD portaient sur MySQL. D'une part ils ne datent pas d'hier ces cours et ma mémoire flanche un peu, ensuite la syntaxe est différente entre MS SQL-Server et MySQL.

    Mais à force je vais bien finir par trouver un début de solution.

  10. #10
    Modérateur

    Profil pro
    dba
    Inscrit en
    Janvier 2010
    Messages
    5 643
    Détails du profil
    Informations personnelles :
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : Janvier 2010
    Messages : 5 643
    Points : 13 092
    Points
    13 092
    Par défaut
    Bonjour,

    Pour adapter la solution proposée par SQLPro a votre besoin réel, à savoir une seul et unique article, vous pouvez créer une table ArticlePublie, fille de la table Article, ne contenant qu'une seule ligne (l'article publié, mais vous l'aurez compris).

    Vous pouvez ensuite soit faire une insertion dans la table article, puis éventuellement un modification dans la table articlePulibe si l'article inséré est à publier, soit créer une vue pour regrouper le tout, et passer par un déclencheur pour faire tout le travail.

    Actuellement, votre colonne "affichage" consomme un octet par ligne dans cette table, alors qu'une seule ligne aura une valeur significative...

    Attention si vous avez appris les triggers sous MySQL : sous SQL Server, les triggers traitent en une fois toutes les lignes visées par l'opération, celles que l'ont trouve dans les pseudos tables INSERTED et DELETED

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2012
    Messages
    49
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Janvier 2012
    Messages : 49
    Points : 38
    Points
    38
    Par défaut
    En effet cela me semble bien compliquer à faire en trigger, j'ai donc utilisé deux requêtes successives qui seront gérées par mon PHP. Je ne peux pas me permettre de passer 2 jours entiers sur un problème aussi insignifiant.

    Voici l'update utilisée:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    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 semble être une action simple que de tester une valeur, mais de fait ça ne l'est pas! ;p

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

  12. #12
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Vu de loin dans le brouillard (en fait en fouillant dans l'aide en ligne):
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    CREATE TRIGGER MyTrigger ON article
    AFTER INSERT
    AS
    update article set affichage = 0 where id <> inserted.id

    A vérifier quand même, je ne connais pas la syntaxe des triggers avec SqlServer (enfin pas encore ).
    Tatayo.

  13. #13
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Chef de projets
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Il manque un cross join entre article et inserted : inserted est une table et non une variable

    Sinon, au risque d'être lourdingue :
    - Que se passe-t-il si le nouvel article ne doit pas être publié ?
    => Actuellement ça va dépublier l'article publié pour rien
    - Que se passe-t-il si on insère en masse plusieurs articles qu'on a indiqué comme devant être publiés ?
    => Là il faut trouver une règle...
    On ne jouit bien que de ce qu’on partage.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 106
    Dernier message: 28/10/2015, 16h09
  2. Réponses: 4
    Dernier message: 14/08/2007, 15h22
  3. Pb Menu : Comment une fois cliqué le style peut rester figé ?
    Par Lolie11 dans le forum Mise en page CSS
    Réponses: 7
    Dernier message: 23/05/2007, 17h13
  4. Créer une fenêtre flottante qui ne peut avoir le focus
    Par BestofMac dans le forum Composants VCL
    Réponses: 4
    Dernier message: 17/07/2002, 10h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo