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

Requêtes PostgreSQL Discussion :

Ajouter une donnée selon un compteur


Sujet :

Requêtes PostgreSQL

  1. #1
    Membre régulier
    Profil pro
    Développeur Web
    Inscrit en
    octobre 2010
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : octobre 2010
    Messages : 149
    Points : 105
    Points
    105
    Par défaut Ajouter une donnée selon un compteur
    Bonjour,
    Je fais une requête SELECT avec une jointure et un group by pour compter le nombre d'éléments associés, ce qui ressemble à ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    select table1.id, table1.name, count(table2.id) as c from table1 left join table2 on table2.link1=table1.id group by table1.id order by table1.name
    J'ai le bon résultat, avec des tableaux contenant [id, name, c].
    Ce qui m'embête c'est qu'en PHP derrière je dois boucler sur tous les résultats pour ajouter une donnée me facilitant l'affichage (une classe CSS), selon si la valeur de 'c' est supérieur à 0 ou non
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    foreach ($data as &$s) {
    	$s['class'] = $s['c'] < 1 ? 'txt-gray' : '';
    }
    Y a-t-il moyen d'ajouter cette donnée directement via PostgreSQL ? Par exemple en ajoutant après 'c' une donnée 'class' avec un test 'if' sur la valeur de 'c' ?

    Merci

  2. #2
    Membre éprouvé
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    septembre 2016
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 676
    Points : 1 295
    Points
    1 295
    Par défaut
    Bonjour,

    si vous attendez qu'on vous aide, merci de faire un tant soit peu de présentation du code.
    le langage SQL n'est sensible ni aux retours lignes, ni aux tabulations, ni aux espaces surnuméraires.

    Une fois présenté votre code ressemble à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    select table1.id
        , table1.name
        , count(table2.id) as c 
    from table1 
        left join table2 
            on table2.link1=table1.id 
    group by table1.id 
    order by table1.name
    Et là c'est évident, la syntaxe est incorrecte aux alentours du Group By

    Ça c'est dit, passons à la demande.

    Que représente 'txt-gray' ?
    Pour moi c'est un assemblage de 2 colonnes : [object] + '-' + [color]
    D'autre part, quand la valeur est > 0 alors le résultat est : "" (chaine vide)
    Que valent chacune des colonnes ?

    Je te rassure on peut tout faire en SQL.
    Pour autant la bonne utilisation du langage est l’utilisation d'une information vectorisée et atomique.

    Si, on pousse ta demande, et en ne prenant pas attention à ce qui vient d'être dit, alors on peut imaginer que la requête SQL délivre directement un flux HTML.

    Pour faire ça tu auras besoin de
    Union All
    Case ... when ... then ...else ...end

    Mais est-ce au SQL de faire ça ?
    Comment va se passer les mises à jour si demain on veut aussi griser le fond et le mettre le texte en Italique ?
    Le savoir est une nourriture qui exige des efforts.

  3. #3
    Membre régulier
    Profil pro
    Développeur Web
    Inscrit en
    octobre 2010
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : octobre 2010
    Messages : 149
    Points : 105
    Points
    105
    Par défaut
    Bonsoir,
    Je ne vois pas le problème aux alentours du group by, ma requête fonctionne d'après mon test à l'instant.
    Désolé si la mise en couleur ne suffit pas à rendre suffisamment lisible le code SQL.

    'class' est un nom de classe CSS, ne correspondant pas à des colonnes, elle est soit vide, soit la chaine 'txt-gray', selon le compteur 'c'.
    J'ai besoin de l'ajouter aux résultats avant de l'envoyer à la couche Vue de mon système MVC. Je me demandais si ce serait pratique que SQL me le fasse puisque c'est déjà lui qui calcule le compteur, au lieu d'avoir sans cesse des foreach sur mes tableaux de résultat.

    Je crée mes requêtes avec une sorte d'ORM et des constantes ou variables PHP qui font que je change la valeur de la chaine de classe sans problème, ce n'est jamais en dur dans la code SQL.

    Case ... when ... then ...else ...end semble bien s'appliquer à ma question.
    Le code suivant donne le résultat que j'attends :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    select table1.id
        , table1.name
        , count(table2.id) as c 
        , case
            when count(table2.id) = 0
            then 'txt-gray'
            else ''
         end
         as class 
    from table1 
        left join table2 
            on table2.link1=table1.id 
    group by table1.id 
    order by table1.name
    Merci pour l'astuce !

  4. #4
    Membre averti
    Homme Profil pro
    developpeur sql et scripting
    Inscrit en
    août 2014
    Messages
    183
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : developpeur sql et scripting
    Secteur : Santé

    Informations forums :
    Inscription : août 2014
    Messages : 183
    Points : 303
    Points
    303
    Par défaut
    Bonjour bonjour,

    Par défaut, un group by qui n'a pas toutes les expressions du select, ca fait mal au cœur.

    Pour votre demande, le sql n'est pas prévu pour faire de l'affichage tout beau tout propre mais pour renvoyer des données d'où le fait que la demande soit pas folichonne.

    Si toutefois vous voulez absolument le faire, quitte à y être, autant encapsuler votre requête dans une CTE (la petite clause WITH), faire un select cte.* et rajouter, dans le select, un case du style
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Case WHEN macolone = madonne THEN null ELSE 'txt-gray' END CSS
    Et voili voilou, comme dirait l'autre.

    Mais ne déportez pas au sql ce que du php ou autre peut faire...

    Bisous bisous

  5. #5
    Membre régulier
    Profil pro
    Développeur Web
    Inscrit en
    octobre 2010
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : octobre 2010
    Messages : 149
    Points : 105
    Points
    105
    Par défaut
    Merci @JeanYvette.
    C'est bien la proposition de Michel.Priori avec CASE qui est dédié à mon cas comme vous le proposez aussi.

    Par contre je ne vois pas l'intérêt de mettre toutes les données du select dans le groupby. Puisqu'en regroupant sur 1 colonne (l'identifiant) ça fait le boulot, pourquoi ajouter des contraintes ou alourdir le groupby alors que ça ne changera pas le résultat ? Peut-être certains cas (jointures plus complexes) peuvent le nécessiter mais je ne comprends pas l'intérêt dans mon exemple. Merci de m'éclairer.

    Et attention à la présentation du code

  6. #6
    Membre éprouvé
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    septembre 2016
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 676
    Points : 1 295
    Points
    1 295
    Par défaut
    Bonjour,


    Citation Envoyé par Titum Voir le message
    Je ne vois pas le problème aux alentours du group by, ma requête fonctionne d'après mon test à l'instant.
    Ah les tests !
    Et que donne celui-ci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    create table test1 
      (id int
      , name varchar(10))
    ;
     
    insert into test1 values
       (1,'Nom impair')
      ,(2,'Nom pair')
      ,(3,'Nom impair')
    ;
     
    select id, name , count(*) as nb
      from test1
      group by id
     ;
    Quelle est votre version de PostgreSQL ?
    Le savoir est une nourriture qui exige des efforts.

  7. #7
    Membre régulier
    Profil pro
    Développeur Web
    Inscrit en
    octobre 2010
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : octobre 2010
    Messages : 149
    Points : 105
    Points
    105
    Par défaut
    Ca provoque une erreur dans votre exemple.
    Mais c'est parce qu'il manque une information, la colonne "id" est une clé primaire. Je crée toujours la colonne d'identifiant sous forme de clé primaire, j'ai omis de le mentionner, ma question ne portais pas sur la structure de ma table.
    Y a-t-il donc plus de logique avec cette info, à ne grouper que sur "id", ou bien je manque encore quelque chose ?

    J'utilise postgreSQL 10.1

  8. #8
    Membre éprouvé
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    septembre 2016
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 676
    Points : 1 295
    Points
    1 295
    Par défaut
    Bonjour,

    Il suffit de pousser les tests et ajouter la contrainte PK pour affiner la compréhension ... compréhension que vous pouvez partager.
    C'est l'objet du forum = l'entraide.

    Entraide :
    principe 1 : "aide toi et le ciel t'aidera"
    principe 2 : "l'exercice du doute permet d'affiner la compréhension"
    principe 3 : "le savoir augmente quand on le partage"
    Le savoir est une nourriture qui exige des efforts.

  9. #9
    Modérateur

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

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : janvier 2010
    Messages : 5 344
    Points : 12 221
    Points
    12 221
    Par défaut
    Bonjour,

    Citation Envoyé par Michel.Priori Voir le message
    Et là c'est évident, la syntaxe est incorrecte aux alentours du Group By
    Citation Envoyé par JeanYvette Voir le message
    Par défaut, un group by qui n'a pas toutes les expressions du select, ca fait mal au cœur.
    La syntaxe du GROUP BY me semble correcte.

    en effet, Titum n'a pas posté la structure de la table en question, mais on peut supposer que la colonne "id" est la clef primaire.
    Dans ce cas, la colonne "nom" dépend fonctionnellement de la colonne "id" et n'a donc pas besoin d'être explicitement précisée dans le GROUP BY.

  10. #10
    Expert éminent
    Homme Profil pro
    Responsable Datas
    Inscrit en
    janvier 2009
    Messages
    4 014
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Datas

    Informations forums :
    Inscription : janvier 2009
    Messages : 4 014
    Points : 9 345
    Points
    9 345
    Par défaut
    Bonjour,
    Je ne sais pas ce qu'il en est de PostgreSQL, mais SqlServer n'est pas d'accord:
    Code sql : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    select cd_c_code,cd_c_nom, count(*) 
    from CLIENT_DETAIL
    group by CD_C_CODE
    cd_c_code est la clé primaire de la table.
    La réponse est sans appel:
    Msg*8120, Niveau*16, État*1, Ligne*1
    La colonne "CLIENT_DETAIL.CD_C_NOM' n'est pas valide dans la liste de sélection parce qu'elle n'est pas contenue dans une fonction d'agrégation ou dans la clause GROUP BY.
    Tatayo.

  11. #11
    Modérateur

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

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : janvier 2010
    Messages : 5 344
    Points : 12 221
    Points
    12 221
    Par défaut
    Citation Envoyé par Michel.Priori Voir le message
    Y a-t-il donc plus de logique avec cette info, à ne grouper que sur "id", ou bien je manque encore quelque chose ?
    Non, c'est bien ça.

    d'après la norme SQL, dans une requete avec regroupement, toute colonne du SELECT doit soit :
    1/ être inclues dans une fonction d'agregation (SUM, MAX,...)
    2/ soit faire partie du regroupement ou dépendre fonctionnellement de celui-ci


    La partie en gras (apparue il me semble dans la norme de 1999) permet effectivement d’omettre la colonne "name" dans cet exemple, à condition que la clef soit effectivement déclarée afin d'assurer la dépendance fonctionnelle.

    A ma connaissance, Postgre est le seul SGBDR a implémenter -correctement (mysql si tu me lis)- cette subtilité.

    Si dans le même exemple (avec la clef primaire sur id déclarée) on fait la même requête mais en regroupant sur la colonne name uniquement, alors on aura une erreur (contrairement à mysql qui renverra... "quelque chose" )

  12. #12
    Modérateur

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

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : janvier 2010
    Messages : 5 344
    Points : 12 221
    Points
    12 221
    Par défaut
    Citation Envoyé par tatayo Voir le message
    Je ne sais pas ce qu'il en est de PostgreSQL, mais SqlServer n'est pas d'accord:
    Oracle non plus, mais avec un message bien plus laconique :
    not a GROUP BY expression

  13. #13
    Membre éprouvé
    Homme Profil pro
    Architecte de base de données
    Inscrit en
    septembre 2016
    Messages
    676
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte de base de données
    Secteur : Conseil

    Informations forums :
    Inscription : septembre 2016
    Messages : 676
    Points : 1 295
    Points
    1 295
    Par défaut
    Bonjour,

    Citation Envoyé par aieeeuuuuu Voir le message
    2/ soit faire partie du regroupement ou dépendre fonctionnellement de celui-ci
    [...]
    A ma connaissance, Postgre est le seul SGBDR a implémenter -correctement (mysql si tu me lis)- cette subtilité.
    Et bien, merci, car moi non plus je n'avais pas connaissance de cette subtilité, qui me semble :
    - légitime du point de vue théorique
    - compliquée à mettre en œuvre lors des jointures multiples (surtout pour la relecture de rq longues)

    J'ai du aller sur le site https://dbfiddle.uk/?rdbms=postgres_10 pour valider le test ; c'est pas que je n'avais pas confiance...
    Le savoir est une nourriture qui exige des efforts.

  14. #14
    Rédacteur
    Avatar de SQLpro
    Homme Profil pro
    YYYY
    Inscrit en
    mai 2002
    Messages
    19 245
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : YYYY
    Secteur : Conseil

    Informations forums :
    Inscription : mai 2002
    Messages : 19 245
    Points : 45 512
    Points
    45 512
    Par défaut
    Citation Envoyé par aieeeuuuuu Voir le message
    d'après la norme SQL, dans une requete avec regroupement, toute colonne du SELECT doit soit :
    1/ être inclues dans une fonction d'agregation (SUM, MAX,...)
    2/ soit faire partie du regroupement ou dépendre fonctionnellement de celui-ci
    Tout à fait....


    La partie en gras (apparue il me semble dans la norme de 1999) permet effectivement d’omettre la colonne "name" dans cet exemple, à condition que la clef soit effectivement déclarée afin d'assurer la dépendance fonctionnelle.
    Je confirme

    A ma connaissance, Postgre est le seul SGBDR a implémenter
    Mais que se passera t-il si la clef évolue ? N'oubliez pas que ce qui fait la force des SGBDR est la facilité d'évolution des structures de données....
    1) la colonne n'est plus la clef primaire => résultat différent potentiellement faux
    2) la clef primaire est augmentée d'une colonne supplémentaire => résultat différent potentiellement faux
    3) quid de la rétro compatibilité avec une version antérieure => résultat différent potentiellement faux

    C'est pour toutes ces raisons et aussi pour une meilleure optimisation que les grand SGBDR ont opté pour un SQL strict et non ce dangereux raccourci !

    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...
    * * * * * Enseignant CNAM PACA - ISEN Toulon - CESI Aix en Provence * * * * *

  15. #15
    Modérateur

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

    Informations professionnelles :
    Activité : dba

    Informations forums :
    Inscription : janvier 2010
    Messages : 5 344
    Points : 12 221
    Points
    12 221
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    Mais que se passera t-il si la clef évolue ? N'oubliez pas que ce qui fait la force des SGBDR est la facilité d'évolution des structures de données....
    1) la colonne n'est plus la clef primaire => résultat différent potentiellement faux
    2) la clef primaire est augmentée d'une colonne supplémentaire => résultat différent potentiellement faux
    3) quid de la rétro compatibilité avec une version antérieure => résultat différent potentiellement faux
    Non, dans ces cas, on aura une erreur :
    Pour les 1/ et 2/, car postgre, à la différence de mysql, vérifie la dépendance fonctionnelle. si la clef change, alors la dépendance fonctionnelle n'est plus vraie, et on aura une erreur.
    pour le cas 3/ pour les anciennes versions, on aura aussi une erreur, pour les mêmes raison que sur les autres SGBDR.

  16. #16
    Modérateur

    Homme Profil pro
    Consultant Teradata
    Inscrit en
    septembre 2008
    Messages
    7 886
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant Teradata

    Informations forums :
    Inscription : septembre 2008
    Messages : 7 886
    Points : 15 734
    Points
    15 734
    Par défaut
    J'aurai opté pour une de ces deux syntaxes de mon côté :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      select t1.id
           , t1.name
           , coalesce((select count(t2.id) from table2 as t2 where t2.link1 = t1.id), 0) as c
        from table1 as t1
    order by t1.name;
     
        select t1.id
             , t1.name
             , coalesce(t2.c, 0) as c
          from table1 as t1
     left join (select link1, count(*) as c from table2 group by link1) as t2 on t2.link1 = t1.id
      order by t1.name;
    Merci aieeeuuuuu pour la règle sur la dépendance fonctionnelle, j'ignorais que PostGre l'avait implémentée (et correctement de surcroît !).

  17. #17
    Membre régulier
    Profil pro
    Développeur Web
    Inscrit en
    octobre 2010
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : octobre 2010
    Messages : 149
    Points : 105
    Points
    105
    Par défaut
    hhmmmm
    J'ai toujours eu une colonne PK dans mes tables sur laquelle j'ai fait les group by sans ajouter la liste (potentiellement longue) des autres colonnes récupérées.
    Et avec MySQL et Postgre je n'ai jamais eu de problème, et je crois bien même avec Firebird il y a quelques années.

    La raison principale je crois c'est qu'en général je groupe sur l'ID de la table principale et que je veux faire un simple comptage sur une table jointe. C'est un cas simple.

    Maintenant en lisant vos commentaires, je conçois que cela peut poser des problèmes. C'est éclairant, merci à tous.

Discussions similaires

  1. [1.x] Ajouter une donnée avant insertion
    Par modogo2000 dans le forum Débuter
    Réponses: 4
    Dernier message: 01/03/2011, 23h21
  2. ajouter une donnée à un dataset existant
    Par L0007 dans le forum Débutez
    Réponses: 5
    Dernier message: 30/09/2010, 15h11
  3. [XL-2000] Afficher une donnée selon champs concatener
    Par JonathanMQ dans le forum Excel
    Réponses: 2
    Dernier message: 29/07/2010, 16h02
  4. [SQL] Comment rechercher une donnée selon un critère !
    Par Il_TiRaNNo dans le forum PHP & Base de données
    Réponses: 12
    Dernier message: 09/05/2007, 15h59
  5. [Cookies] Ajouter une donnée à un cookie
    Par jack1234 dans le forum Langage
    Réponses: 2
    Dernier message: 14/01/2006, 20h58

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