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

Langage SQL Discussion :

Croisement d'une table avec elle même


Sujet :

Langage SQL

  1. #1
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2
    Points : 1
    Points
    1
    Par défaut Croisement d'une table avec elle même
    Bonjour,

    J'espère que ce petit problème vous intéressera, je cherche à comprendre comment croiser une table avec elle ? voilà où j'en suis arrivé...
    La table est constituée comme suit : pour l'exemple nous l'appelerons Table des commandes ->tab_commande

    Numéro de client : num_client - type int(4)
    date de commande : date_commande - type date

    J'ai donc toutes mes données de commandes pour l'année 2004 et pour l'année 2005.

    Je cherche tous les clients qui n'ont pas commandé sur une plage de dates par rapport à une plage de dates de référence. Exemple : quels sont les clients qui ont commandé entre le 1/1/2004 et le 31/12/2004 (Periode_1) et qui n'ont pas commandé au mois de janvier 2005 (1/1/2005 au 31/12/2005) Periode_2;

    Je remercie au passage l'excellentissime didac de SQLPRO sur la manière de penser le NULL.

    Voilà à quoi ressemble ma requête et les questions que je me pose :

    SELECT Periode_2.*,Periode_1.* from tab_commande AS Periode_1
    LEFT JOIN tab_commande AS Periode_2
    ON
    Periode_1.num_client=Periode_2.num_client
    AND
    Periode_1.date_commande BETWEEN '#2004/01/01#'
    AND '#2004/12/31#'
    AND
    Periode_2.date_commande BETWEEN '#2005/01/01#'
    AND '#2005/01/31#'
    WHERE ISNULL Periode_1
    AND
    Periode_2.date_commande BETWEEN '#2005/01/01#'
    AND '#2005/01/31#'

    Je décompose la requête comme je l'ai pensé (à plusieurs...lol) :
    Une requête externe gauche afin de récupérer les null de non jointure à la table de droite (la jointure sert ici à récupérer à terme les "non joints" à la table de gauche...).
    Comme je ne veux pas que toute la table soit croisée sur elle même, j'ajoute la définition des plages de date dans le join, la jointure externe gauche préservant les non jointures;
    Cependant, comme il se peut que certains row retournés soient de la forme :
    Periode_2.num_client | Periode_2.date_commande|Periode_1.num_client
    4657 2005/02/01 NULL

    La clause ON dans laquelle j'ai inclu les between ne tri pas ces dates puisque Periode_1.num_client est null (la jointure externe gauche préserve les NULL, comme SQLPRO l'indique, le NULL n'étant pas une valeur, elle n'est pas 'comparable'), je réinclu donc le même BETWEEN dans la clause WHERE sur Periode_2.date_commande.
    Le ISNULL dans la clause WHERE ramenant donc bien les clients n'ayant pas fait de commande sur Periode_2 par rapport à Periode_1.

    J'espère avoir été clair... maintenant mes questions :
    1 - Optimisation par le moteur de requête :
    Les deux clauses BETWEEN dans le ON sont-elles bien prises en compte pour ne croiser que les row des deux périodes concernées ?
    Sur une table de plus d'1 million d'enregistrement, je préfèrerais ne demander que le croisement d'un mois avec un autre mois... et pas de toute la table sur elle même...

    2 - Position du ISNULL Periode_1
    J'ai commancé par le mettre dans le WHERE mais maintenant, je ne sais pas pourquoi, je le placerais bien dans la clause ON (après les deux BETWEEN). J'ai essayé et le résultat n'est pas concluant (résultats erronés), pourquoi ? Quelle différence cela peut-il bien faire qu'il soit placé dans l'une ou dans l'autre position.

    Souhaitant avoir aiguisé votre curiosité et vous remerciant par avance du temps forcément nécessaire pour se pencher sur les exemples et les explications des "autres".

    Merci d'avance

  2. #2
    Inactif   Avatar de Médiat
    Inscrit en
    Décembre 2003
    Messages
    1 946
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 946
    Points : 2 227
    Points
    2 227
    Par défaut
    La requête suivante me paraît plus lisible :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT num_client 
    FROM tab_commande a
    WHERE date commande BETWEEN  '#2004/01/01#' AND '#2004/12/31#' 
      AND NOT EXISTS (SELECT NULL
                      FROM tab_commande b
                      WHERE b.num_client = a.num_client
                        AND date_commande BETWEEN '#2005/01/01#' AND '#2005/01/31#' )
    GROUP BY num_client
    J'ai mis le GROUP BY parce que la question est "Je cherche tous les clients ", mais il n'est pas obligatoire, si l'on veut les détails.

    Différence de résultats entre le WHERE et le ON : pour une jointure interne, aucune, pour une jointure externe, par contre, les conditions du WHERE sont contraignantes pour toutes les lignes ramenées par la jointures, alors que les conditions du ON ne sont contraigantes que pour la table de gauche pour un LEFT OUTER JOIN.
    Exemple d'erreur très courante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    FROM a LEFT OUTER JOIN b ON a.id = b.id
    WHERE b.champ = 'bleu'
    Ici la jointure externe ne sert à rien puisque les lignes 'ajoutées' auront b.champ à NULL donc pas égal à 'bleu'
    par contre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    FROM a LEFT OUTER JOIN b ON  a.id = b.id
                             AND b.champ = 'bleu'
    il y aura une ligne ajoutée si il n'existe pas de ligne de b avec le même id et en plus la colonne champ = 'bleu'
    J'affirme péremptoirement que toute affirmation péremptoire est fausse
    5ième élément : barde-prince des figures de style, duc de la synecdoque
    Je ne réponds jamais aux questions techniques par MP

  3. #3
    Nouveau Candidat au Club
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 2
    Points : 1
    Points
    1
    Par défaut
    Merci beaucoup pour la réponse, mais ....

    1 - Effectivement, c'est tellement plus lisible !

    2 - Est-elle plus efficace en terme d'optimisation de requête ?

    3 - Ma version de travail de Mysql est une version inférieure à la 4.1 qui ne gère pas le subselect dans les requêtes select... si les tests du 2- s'avèrent concluants, je ferais migrer mon serveur.

    4 - Super merci,

    5 - Existerait-il par là, un bouquin, un topo, sur les optimiseurs de requêtes et les requêtes "avancées" ? Une référence de bouquin sur SQL (pas une initiation, merci ;-) )?

    Bonne journée

Discussions similaires

  1. [Modèle Relationnel] jointure d'une table avec elle-même
    Par johnny3 dans le forum Schéma
    Réponses: 11
    Dernier message: 26/04/2015, 00h15
  2. [CakePHP] Association d'une table avec elle même
    Par kibla dans le forum Bibliothèques et frameworks
    Réponses: 6
    Dernier message: 12/12/2009, 15h11
  3. Table de jointure d'une entité avec elle-même
    Par Danger dans le forum Hibernate
    Réponses: 0
    Dernier message: 15/05/2009, 21h13
  4. [SQL2K] delete cascade d'une table sur elle même
    Par StormimOn dans le forum MS SQL Server
    Réponses: 4
    Dernier message: 25/04/2006, 16h28
  5. [arborescence] jointure d'une table avec elle même ?
    Par Celelibi dans le forum Requêtes
    Réponses: 2
    Dernier message: 16/11/2004, 18h48

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