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

Requêtes PostgreSQL Discussion :

Comment comptabiliser un NULL comme une valeur 0 ?


Sujet :

Requêtes PostgreSQL

  1. #1
    Membre éclairé
    Avatar de clavier12AZQSWX
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2009
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 392
    Points : 863
    Points
    863
    Par défaut Comment comptabiliser un NULL comme une valeur 0 ?
    bonjour,

    j'ai besoin qu'une requête qui ne renvoie rien me renvoie la valeur 0, comment faire ?

    voici ma requête :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    select *
    from matable
    where 0=(select count(*) from matable2))
    si j'ai rien dans ma table2, alors ma sous-requête renvoie RIEN (ou null ?)
    Or ma condition 0=RIEN n'est pas validé alors que je le voudrais.

    comment faire ?

    ps: le fait qu'un count(*) ne renvoie pas forcément un entier est-il une particularité de postgresql ou bien une règle du sql ?

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    bonjour,

    si votre table2 est vide, le count(*) retournera 0.

    donc votre condition sera vérifiée

  3. #3
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 080
    Points : 30 803
    Points
    30 803
    Par défaut
    Si j'ai bien compris, tu veux retourner le contenu de matable si matable2 est vide...
    Comme cela, ce sera sans doute plus efficace :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT  *
    FROM    matable
    WHERE   NOT EXISTS
            (   SELECT  1
                FROM    matable2
            )
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  4. #4
    Membre éclairé
    Avatar de clavier12AZQSWX
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2009
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 392
    Points : 863
    Points
    863
    Par défaut
    non je veux que que le retour de ma requete imbriqué soit égale à 0 si la requête imbriqué ne renvoit rien (soit car elle est vide, soit car la condition ne permet aucun tupe).
    j'ai pas mis de condition dans mon exemple pour simplifier mon exemple. j'aurai pu écrire cela aussi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT * FROM matable WHERE 0=(SELECT count(*) FROM matable2 where monchamp=2))
    Et comme aucun tuple de table2 ne satisfait la condition monchamp=2, alors la count(*) ne renvoie rien hélas au lieu de renvoyer 0.

  5. #5
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    create table tb1 (id integer);
    insert into tb1 values (1);
     
    select count(*) from tb1 where id = 2;
    Résultat :
    Quelle est la vrai requete ?
    Quel version de postgres utilisez vous ?

  6. #6
    Membre éclairé
    Avatar de clavier12AZQSWX
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2009
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 392
    Points : 863
    Points
    863
    Par défaut
    Citation Envoyé par punkoff Voir le message
    Quelle est la vrai requete ?
    Quel version de postgres utilisez vous ?
    pg 8.2 et je ne peux pas upgrader en 8.3, hors de question.

  7. #7
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 080
    Points : 30 803
    Points
    30 803
    Par défaut
    Si le count(*) dans la sous-requête renvoie 0, c'est bien que cette sous-requête ne retourne aucune ligne ?
    Sinon, donne nous un jeu de données et un exemple réel de ce que tu attends comme comportement.
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  8. #8
    Membre éclairé
    Avatar de clavier12AZQSWX
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2009
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 392
    Points : 863
    Points
    863
    Par défaut
    là je ne suis pas au travail.
    mais j'ai trouvé deux sujets qui ont la même problématique :

    premier

    second

    On conseille d'utiliser COALESCE pour obtenir 0 si la sous requête ne retourne rien (ou n'a rien eu à retourner).

    et peut-être ma réponse ici même
    http://www.developpez.net/forums/d88...-resultat-nul/

    demain j'essaierai.
    miam, vivement demai !

  9. #9
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Je ne vois pas bien le rapport.

    Vous partez de l'hypothèse que votre sous-requete :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    select count(*) from ma_table where ma_col = 'X'
    Retourne NULL

    Ceci est, de mon point de vue, faux.

    Donc au choix :
    - la v8.2 traite les count(*) d'une manière très particulière (j'ai un doute)
    - vous ne nous présentez pas la requête que vous executez.

    cf le 2nd exemple que vous avez linkez. La personne en question ne comprend pas ce qu'elle fait et utilise un coalesce / sous-requête alors qu'il n'y en a pas besoin.

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    1 874
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 874
    Points : 2 890
    Points
    2 890
    Par défaut
    Comme dit par punkoff, cette discussion repose sur un faux problème, car
    • count(*) ne renvoie pas null mais 0 quand il n'y a pas d'enregistrement correspondant
    • select count(*) from... ne renvoie pas de résultat vide (aucune ligne) mais toujours une ligne.

  11. #11
    Membre éclairé
    Avatar de clavier12AZQSWX
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2009
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 392
    Points : 863
    Points
    863
    Par défaut
    pour infos, voiçi ma requête qui ne renvoit pas 0 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT count(a.name) 
    FROM cpn_hr_employee a,cpn_hr_employee_circuit b 
    WHERE a.id=b.employee_id  AND b.shop_id=1 
    AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31' 
    AND 0=(SELECT count(*) FROM cpn_hr_employee a2,cpn_hr_employee_circuit b2 WHERE a2.id=b2.employee_id  AND a2.id=a.id AND b2.begin_date> '2012-05-31'  AND b2.shop_id=b.shop_id ) 
    AND 0=(SELECT count(*) FROM cpn_hr_employee a3,cpn_hr_employee_circuit b3 WHERE a3.id=b3.employee_id  AND b3.begin_date<='2012-05-31' AND b3.end_date is null  AND b3.shop_id=b.shop_id )  
    GROUP BY a.name ORDER BY a.name

  12. #12
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 080
    Points : 30 803
    Points
    30 803
    Par défaut
    En voyant ta requête, je constate deux choses :
    1. Tu n'utilises pas la syntaxe normalisée pour les jointures, ce qui rend ton code peu lisible
    2. Tu n'avais pas précisé que tu utilisais une sous-requête corrélée c'est à dire liée à la requête principale par un filtre, ce qui en change profondément le fonctionnement

    En effet une sous requête corrélée utilisée dans le filtre se comporte comme une jointure avec la table principale.

    Voici ta requête remise en forme en respectant la syntaxe conseillée et normalisée depuis 20 ans :
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    SELECT  COUNT(a.name) 
    FROM    cpn_hr_employee         a
        INNER JOIN
            cpn_hr_employee_circuit b
            ON  a.id = b.employee_id
    WHERE   b.shop_id = 1 
        AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31' 
        AND 0 = (   SELECT  COUNT(*) 
                    FROM    cpn_hr_employee         a2  
                        INNER JOIN
                            cpn_hr_employee_circuit b2
                            ON  a2.id = b2.employee_id
                    WHERE   b2.begin_date   > '2012-05-31'
                        AND a2.id       = a.id
                        AND b2.shop_id  = b.shop_id
                )
        AND 0 = (   SELECT  COUNT(*)
                    FROM    cpn_hr_employee         a3
                        INNER JOIN
                            cpn_hr_employee_circuit b3
                            ON  a3.id = b3.employee_id
                    WHERE   b3.begin_date   <= '2012-05-31'
                        AND b3.end_date IS NULL
                        AND b3.shop_id  = b.shop_id 
                )  
    GROUP BY a.name
    ORDER BY a.name
    Je ne me suis pas penché sur le côté fonctionnel... mais il y aurait sans doute à redire.
    Ne serait-ce que sur SELECT COUNT(a.name) ... GROUP BY a.name qui, en toute logique, ne devrait pas retourner autre chose que 1 sur chaque ligne sélectionnée.

    Voici la manière dont elle se comporte :
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    SELECT  COUNT(a.name) 
    FROM    cpn_hr_employee         a
        INNER JOIN
            cpn_hr_employee_circuit b
            ON  a.id = b.employee_id
        INNER JOIN
            (   SELECT  a2.id
                    ,   b2.shop_id  
                    ,   COUNT(*)    AS cnt 
                FROM    cpn_hr_employee         a2  
                    INNER JOIN
                        cpn_hr_employee_circuit b2
                        ON  a2.id = b2.employee_id
                WHERE   b2.begin_date   > '2012-05-31'
                GROUP BY a2.id
                    ,   b2.shop_id
            )   sr1
            ON  sr1.id       = a.id
            AND sr1.shop_id  = b.shop_id
        INNER JOIN
            (   SELECT  b3.shop_id
                    ,   COUNT(*)    AS cnt
                FROM    cpn_hr_employee         a3
                    INNER JOIN
                        cpn_hr_employee_circuit b3
                        ON  a3.id = b3.employee_id
                WHERE   b3.begin_date   <= '2012-05-31'
                    AND b3.end_date IS NULL
                GROUP BY b3.shop_id
            )   sr2
            ON  sr2.shop_id  = b.shop_id
    WHERE   b.shop_id = 1
        AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31'
        AND sr1.cnt = 0
        AND sr2.cnt = 0
    GROUP BY a.name
    ORDER BY a.name
    Et là, en effet, tu ne peux jamais obtenir de résultat.
    Comment obtenir un comptage nul d'une requête de la forme SELECT id, COUNT(*) FROM tbl GROUP BY id ?

    Si tu veux obtenir le résultat attendu, il faut passer par NOT IN ou NOT EXISTS.
    Ce qui donnerait quelque chose comme cela :
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    SELECT  COUNT(a.name) 
    FROM    cpn_hr_employee         a
        INNER JOIN
            cpn_hr_employee_circuit b
            ON  a.id = b.employee_id
    WHERE   b.shop_id = 1 
        AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31' 
        AND NOT EXISTS
            (   SELECT  1   
                FROM    cpn_hr_employee         a2  
                    INNER JOIN
                        cpn_hr_employee_circuit b2
                        ON  a2.id = b2.employee_id
                WHERE   b2.begin_date   > '2012-05-31'
                    AND a2.id       = a.id
                    AND b2.shop_id  = b.shop_id
            )
        AND b.shop_id   NOT IN
            (   SELECT  b3.shop_id
                FROM    cpn_hr_employee         a3
                    INNER JOIN
                        cpn_hr_employee_circuit b3
                        ON  a3.id = b3.employee_id
                WHERE   b3.begin_date   <= '2012-05-31'
                    AND b3.end_date IS NULL
            )  
    GROUP BY a.name
    ORDER BY a.name
    ;
    Pour plus d'informations, je te renvoie aux cours SQL
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  13. #13
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 770
    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 770
    Points : 52 726
    Points
    52 726
    Billets dans le blog
    5
    Par défaut
    Citation Envoyé par al1_24 Voir le message
    ...
    Je ne me suis pas penché sur le côté fonctionnel... mais il y aurait sans doute à redire.
    Ne serait-ce que sur SELECT COUNT(a.name) ... GROUP BY a.name qui, en toute logique, ne devrait pas retourner autre chose que 1 sur chaque ligne sélectionnée.
    D'accord sa requête est ultra pourrie et il faudrait sans doute qu'il commence à apprendre le SQL. Mais de là à lui donner de fausses informations....

    En effet
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SELECT COUNT(a.name) FROM a GROUP BY a.name
    Peut renvoyer des lignes différentes de 1 si il y a des doublons de a.name !!!

    C'est sans doute une requête débile, mais pas délirante....
    OK la différence est subtile !

    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/ * * * * *

  14. #14
    Membre éclairé
    Avatar de clavier12AZQSWX
    Homme Profil pro
    Technicien maintenance
    Inscrit en
    Avril 2009
    Messages
    1 392
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Somme (Picardie)

    Informations professionnelles :
    Activité : Technicien maintenance

    Informations forums :
    Inscription : Avril 2009
    Messages : 1 392
    Points : 863
    Points
    863
    Par défaut
    o la pas amigos,
    pas de de cris, j'ai fais un mauvais copié coller. (j'ai une requête qui compte et une autre qui liste).

    donc celle qui liste que j'utilisais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT a.name
    FROM cpn_hr_employee a,cpn_hr_employee_circuit b 
    WHERE a.id=b.employee_id  AND b.shop_id=1 
    AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31' 
    AND 0=(SELECT count(*) FROM cpn_hr_employee a2,cpn_hr_employee_circuit b2 WHERE a2.id=b2.employee_id  AND a2.id=a.id AND b2.begin_date> '2012-05-31'  AND b2.shop_id=b.shop_id ) 
    AND 0=(SELECT count(*) FROM cpn_hr_employee a3,cpn_hr_employee_circuit b3 WHERE a3.id=b3.employee_id  AND b3.begin_date<='2012-05-31' AND b3.end_date IS NULL  AND b3.shop_id=b.shop_id )  
    GROUP BY a.name ORDER BY a.name
    et j'ai trouvé mon problème (j'ai oublié de joindre les sous-requête (celle avec 0=....) avec ma table principale du haut).

    après correction, tout fonctionne nickel !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    SELECT a.name
    FROM cpn_hr_employee a,cpn_hr_employee_circuit b 
    WHERE a.id=b.employee_id  AND b.shop_id=1 
    AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31' 
    AND 0=(SELECT count(*) FROM cpn_hr_employee a2,cpn_hr_employee_circuit b2 WHERE a2.id=b2.employee_id AND b2.employee_id=b.employee_id AND a2.id=a.id AND b2.begin_date> '2012-05-31'  AND b2.shop_id=b.shop_id ) 
    AND 0=(SELECT count(*) FROM cpn_hr_employee a3,cpn_hr_employee_circuit b3 WHERE a3.id=b3.employee_id  AND b3.employee_id=b.employee_id  AND b3.begin_date<='2012-05-31' AND b3.end_date IS NULL  AND b3.shop_id=b.shop_id )  
    GROUP BY a.name ORDER BY a.name
    Avec mon erreur, les conditions 0=(select...) renvoyait toujours un résultat qui ne me satisfsait pas (car prenait en compte la globalité des employee, au lieu de celui en cours).

    Pour la petite histoire (ou la grande), sachez j'utilisais une vieille version de pgmadmin sous linux qui n'affiche pas 0 quand un count renvoit 0 mais une ligne blanche (d'où ma comprehension d'un résultat null ou vide) !

    ps : j'ai bien noter la conformité de la syntaxe sql conseillée, mon écriture est volontaire car la requête est plus "sémantiquement lisible" par une tiers-personne (je vous ai privé des commentaires entre les AND).

    Alors que la requêtre normalisée (avec inner...) est illisible sans se plonger harduement dedans. Je ne suis pas adepte de l'optimisation mais de la simplification.

  15. #15
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 080
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 63
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 080
    Points : 30 803
    Points
    30 803
    Par défaut
    Citation Envoyé par Michael REMY Voir le message
    Je ne suis pas adepte de l'optimisation mais de la simplification.
    Le jour où on doit travailler avec des tables contenant des milliards de lignes sur un serveur sous-taillé, on change de manière de voir
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  16. #16
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Mai 2002
    Messages
    3 173
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2002
    Messages : 3 173
    Points : 5 345
    Points
    5 345
    Par défaut
    Citation Envoyé par Michael REMY Voir le message
    Alors que la requêtre normalisée (avec inner...) est illisible sans se plonger harduement dedans. Je ne suis pas adepte de l'optimisation mais de la simplification.
    Qu'est-ce qui faut pas entendre.

    Indentez vos requête et la lisibilité sera de mise.

    Ne pas utiliser des inner join c'est augmenter les risques d'oublier des jointures.

    C'est une perte de temps pour le developpeur, et pour celui qui va faire la maintenance.

    Il sera obliger de checker manuellement les jointures une à une pour comprendre la requête.
    C'est donc ça une requête lisible et simple ?


    De plus, pgsql est pas terrible au nivaeu des fonctions count, dans ce cas précis il faut utiliser un NOT EXISTS comme proposé par al1_24 au tout début de ce poste.

    Bref en reworkée :
    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
    16
    17
    18
    19
    20
    21
     
    SELECT a.name
    FROM cpn_hr_employee a
    inner join cpn_hr_employee_circuit b on a.id=b.employee_id
    WHERE b.shop_id=1 AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31' 
    AND not exists 
    	(
    		SELECT null 
    		FROM cpn_hr_employee a2
    		inner join cpn_hr_employee_circuit b2 on a2.id=b2.employee_id 
    		WHERE b2.employee_id=b.employee_id AND a2.id=a.id AND b2.begin_date> '2012-05-31'  AND b2.shop_id=b.shop_id 
    	) 
    AND not exists 
    	(
    		SELECT null 
    		FROM cpn_hr_employee a3
    		inner join cpn_hr_employee_circuit b3 on a3.id=b3.employee_id  
    		where b3.employee_id=b.employee_id  AND b3.begin_date <= '2012-05-31' AND b3.end_date IS NULL  AND b3.shop_id=b.shop_id 
    	)  
    GROUP BY a.name 
    ORDER BY a.name

    De là on peut voir les étapes inutiles de la requête :
    - 2 not exists ne servent à rien, 1 seul suffirait
    - Le group by ne sert à rien
    - on peut aussi se demander l'utilité de la jointure sur la table b
    - des jointures sont inutiles

    Donc on recommence :
    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
    16
    17
     
    SELECT distinct a.name
    FROM cpn_hr_employee a
    WHERE  exists 
    	(
    		select null
    		from cpn_hr_employee_circuit b 
    		where a.id=b.employee_id b.shop_id=1 AND b.real_end_date BETWEEN '2012-05-01' AND '2012-05-31' 
    		and not exists 
    			(
    				select null 
    				from cpn_hr_employee_circuit b2 
    				where b2.employee_id=b.employee_id AND b2.shop_id=b.shop_id 
    				and (b2.begin_date> '2012-05-31' or (b2.begin_date <= '2012-05-31' AND b2.end_date IS NULL))
    			)		
    	)
    ORDER BY a.name
    Et là on se pose la question de l'utilité du distinct...

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 03/05/2011, 12h40
  2. Comment afficher un seul contour à une valeur particulière
    Par developpeur82 dans le forum MATLAB
    Réponses: 5
    Dernier message: 11/04/2007, 18h13
  3. Réponses: 10
    Dernier message: 24/05/2006, 05h35
  4. Réponses: 4
    Dernier message: 18/04/2006, 18h42
  5. comment vérifier la présence d'une valeur ds une chaîne ?
    Par lidouka dans le forum Langage SQL
    Réponses: 4
    Dernier message: 12/03/2006, 07h01

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