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 MySQL Discussion :

Logique sur une requête MySQL


Sujet :

Requêtes MySQL

  1. #1
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    99
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 99
    Points : 74
    Points
    74
    Par défaut Logique sur une requête MySQL
    Bonjour,

    J'ai besoin de récupérer un tableau php constituées de ligne correspondant à des documents.
    Pour un besoin spécifique, je dois filtrer ces documents, mais là je me trouve confronté à un besoin que je ne sais pas transcrire en logique, peut être que cela vient de la structure de la base, mais je ne peux pas y toucher. Il me reste toujours la possibilité d'un traitement php, mais comme le nombre de lignes est important, je vais vraiment y perdre en terme d'efficacité.

    La structure:
    Table des Documents: DOC
    avec une clef primaire:
    DOC_ID
    ...

    Table Référencement
    avec une clef primaire:
    DTR_ID
    un clef étrangère vers la table DOC
    DTR_DOC_ID
    une date de suppression en cas de référencement supprimé (sinon NULL).
    DTR_DELETE_DATE
    ...

    Un document peut avoir 0 ou plusieurs référencements.

    Et vla ti pa qu'aujourd'hui on me demande de lister tous les documents non référencés. Ok pas de problème, je fais un left join et c'est tout bon:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    SELECT * FROM  DOC
    INNER JOIN  DTR ON DOC.DOC_ID = DTR.DTR_DOC_ID
    WHERE DTR.DTR_DOC_ID IS NULL ;
    Oui, mais là il y a des petits malins qui passent au travers de la requête:
    Tous les documents qui n'ont que des référencements supprimés. Ils ne représentent qu'un pourcentage très faible, mais doivent être obligatoirement listés, sinon ma requête n'est pas complètement valide...
    Et là, pour ce petit nombre de Gaulois, je me sens obligé de passer par des traitements dans des boucles et autres tests enchainés...

    En terme logique, je voudrais récupérer tous les documents qui n'ont pas de référencement, ou qui n'ont aucun référencement pas supprimés.
    S'il vous plait, dites moi que j'ai raté un cours de logique en SQL et qu'il y a une solution SQL propre pour moi !!!

    D'avance merci pour votre aide.

  2. #2
    Membre expérimenté
    Homme Profil pro
    Développeur C++
    Inscrit en
    Avril 2012
    Messages
    771
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur C++
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2012
    Messages : 771
    Points : 1 631
    Points
    1 631
    Par défaut
    Bonsoir,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT * FROM  DOC
    LEFT JOIN  DTR ON DOC.DOC_ID = DTR.DTR_DOC_ID
    WHERE DTR.DTR_DOC_ID IS NULL
    L'opérateur INNER JOIN signifie jointure interne,

    pour faire une jointure externe il faut utiliser LEFT JOIN ou RIGHT JOIN.

    Je te renvoi vers le cours de SQLPRO sur les jointures explique tous les types de jointures existant.

  3. #3
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    99
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 99
    Points : 74
    Points
    74
    Par défaut
    Bonjour Exia,

    Merci pour la réponse. Cela corrige ma première requête et là rend plus logique, mais cela ne répond pas à ma problématique (Si réponse il y a).

    J'ai lu (relu en faite) le tuto sur les jointures de F. Brouard. Mais je ne vois pas d'exemple correspondant à mon besoin.
    En repartant de ces exemples de jointure, il faudrait ajouter une notion de téléphone supprimé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Table Client      Table_Telephone
    CLIENT ID         TEL_NUMERO    TEL_DELETED_DATE
    1                     44 54              NULL
    2                     44 55              NULL
    2                     44 56              NULL
    3                     NULL               NULL
    4                     44 57              2013-01-05
    4                     44 58              NULL
    5                     44 59              2013-01-15
    Avec le Join j'arrive à récupérer les infos comme indiquées ci-dessus.
    En mettant une clause "WHERE TEL_NUMERO IS NULL" je récupère bien tous les clients pour lesquels je n'ai pas de numéro. Mais je ne récupère pas le 5 qui est un client qui a eu un numéro, mais qui ne l'a plus. Et c'est ça qui m'intéresserait.
    Même si je dois faire une 1ère requête pour récupérer les client sans aucun numéro de téléphone (Requête avec le LEFT JOINT) puis une seconde pour récupérer les clients comme celui à l'ID 5.

    Merci pour ton (votre) aide.

  4. #4
    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,

    Non, il faut ajouter la vérification de nullité dans la jointure :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT * FROM  DOC
    LEFT JOIN  DTR 
        ON DOC.DOC_ID = DTR.DTR_DOC_ID
        AND DTR.DTR_DELETE_DATE IS NULL
    WHERE DTR.DTR_DOC_ID IS NULL

  5. #5
    Membre expérimenté
    Homme Profil pro
    Développeur C++
    Inscrit en
    Avril 2012
    Messages
    771
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur C++
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2012
    Messages : 771
    Points : 1 631
    Points
    1 631
    Par défaut
    Donc tu veut une requête qui remonte tous les documents qui ont :
    • TEL_NUMERO est égale à NULL
    • Ou
    • TEL_DELETED_DATE différent de NULL

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT * FROM  DOC
    LEFT JOIN  DTR ON DOC.DOC_ID = DTR.DTR_DOC_ID
    WHERE DTR.DTR_DOC_ID IS NULL OR DTR.DTR_DELETE_DATE IS NOT NULL
    Petite précision le SELECT * doit être utilisé seulement lorsque tu créer ta requête, dans ton application écrit chaque colonne nécessaire pour que ta requête soit plus claire et qu'elle ne remonte pas d'information inutile à chaque fois.

  6. #6
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    99
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 99
    Points : 74
    Points
    74
    Par défaut
    Merci à tous les 2 pour vos réponses, on se rapproche mais nous n'y sommes pas encore.

    Exia,
    TEL_NUMERO est égale à NULL
    Ou
    TEL_DELETED_DATE différent de NULL
    N'est pas complet, car cette requête me renverrai l'id client 4 de l'exemple. Hors le client 4 a bien un numéro actif.

    Aieuuuuu,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT * FROM  DOC
    LEFT JOIN  DTR 
        ON DOC.DOC_ID = DTR.DTR_DOC_ID
        AND DTR.DTR_DELETE_DATE IS NULL
    WHERE DTR.DTR_DOC_ID IS NULL
    Si je lis ta requête j'ai l'impression qu'elle va me renvoyer tous les documents qui ont un référencement actif, hors il me faut exactement le contraire. Ce qui pourrait être déjà intéressant, car au lieu de faire des parcours de tableau de php, il faudrait que je récupère tous les documents non retournés par cette requête.

    Si je retranscris ta requête avec client et téléphone:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT * FROM  CLIENT CLI
    LEFT JOIN  TELEPHONE TEL
        ON CLI.ID = TEL.CLIENT_ID
        AND TEL.DELETED_DATE IS NULL
    WHERE TEL.CLIENT_ID IS NULL
    Pour moi, je vais récupérer 1,2 et 4.

    Par rapport à l'exemple client/téléphone, je voudrais une requête SQL qui me retourne le client 3 et 5.

    Encore merci à vous.

  7. #7
    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
    Citation Envoyé par Leduc08 Voir le message
    Si je lis ta requête j'ai l'impression qu'elle va me renvoyer tous les documents qui ont un référencement actif, hors il me faut exactement le contraire.
    L'as-tu testée ?

    reprenons du début :
    1/ la liste des documents
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SELECT *
    FROM DOC
    2/ La Liste des documents, avec leur(s) référencement(s) respectif(s)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT *
    FROM DOC
    INNER JOIN DTR 
        ON    DTR.DTR_DOC_ID = DOC.DOC_ID
    3/ La liste des documents avec leurs référencement actifs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT *
    FROM DOC
    INNER JOIN DTR 
        ON    DTR.DTR_DOC_ID = DOC.DOC_ID
        AND  DTR.DTR_DELETE_DATE IS NULL
    Avec cette requête, du fait de la jointure interne, les documents n'ayant pas de référencement actif ne seront pas dans le résultat.

    4/ Remplaçons par une jointure externe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT *
    FROM DOC
    LEFT OUTER JOIN DTR 
        ON    DTR.DTR_DOC_ID = DOC.DOC_ID
        AND  DTR.DTR_DELETE_DATE IS NULL
    Nous obtenons tous les documents et leurs référencements actifs, les colonnes de la table DTR pour les document n'ayant pas de référencement actif seront marquées à NULL (bref une jointure externe quoi ! )
    Et justement, ce sont ces documents que l'on veut, mais seulement ceux-la, il suffit donc d'ajouter le filtre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    SELECT *
    FROM DOC
    LEFT OUTER JOIN DTR 
        ON    DTR.DTR_DOC_ID = DOC.DOC_ID
        AND  DTR.DTR_DELETE_DATE IS NULL
    WHERE DTR_ID IS NULL
    Il est cependant possible de faire autrement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    SELECT *
    FROM DOC
    WHERE NOT EXISTS(
        SELECT 1
        FROM DTR
        WHERE DTR_DOC_ID = DOC.DOC_ID
        AND DTR_DELETE_DATE IS NULL
    )

  8. #8
    Membre régulier
    Inscrit en
    Juin 2008
    Messages
    99
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 99
    Points : 74
    Points
    74
    Par défaut
    A la première écriture de mon ma précédente réponse, j'avais noté:
    "Comme je ne suis pas certains de comprendre tous les mécanismes de ta requête, je vais la tester, et je reviens vers toi..."
    Puis à la relecture, j'ai d'un seul coup eu l'impression de la comprendre (pas peu fier en plus le gars...). Du coup j'ai supprimé cette partie du message, et je l'ai remplacé par ce que tu as lu. Honte sur moi. Quand on ne sait pas, on test !!!

    Tes 2 requêtes répondent exactement à ce que je voulais.
    Un grand merci à toi et à Exia pour le temps passé à me lire et à répondre.

    A++

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

Discussions similaires

  1. [DEBUTANT] Besoin d'aide sur une requête Mysql
    Par Nerone21 dans le forum Requêtes
    Réponses: 3
    Dernier message: 05/09/2008, 14h01
  2. [MySQL] texte qui bloque sur une requéte mysql
    Par leto02 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 28/11/2007, 12h32
  3. problème sur une requête mysql
    Par atomikado dans le forum Requêtes
    Réponses: 4
    Dernier message: 05/10/2007, 17h04
  4. Condition logique sur une requête
    Par NiKoS29 dans le forum Requêtes et SQL.
    Réponses: 11
    Dernier message: 25/07/2007, 16h40
  5. besoin d'aide sur une requête mysql
    Par unmulot dans le forum Langage SQL
    Réponses: 5
    Dernier message: 07/07/2006, 14h17

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