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 :

Requête complexe sur plusieurs table


Sujet :

Langage SQL

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 12
    Points : 8
    Points
    8
    Par défaut Requête complexe sur plusieurs table
    Bonjour tout le monde

    Je suis nouveau sur ce forum, alors si jamais l'allure de mes messages ne convient pas, soyez indulgent.

    Bon voici mon problème. Manquant peut-être d'un peu d'expérience en SQL je bloque sur une requête assez complexe que je dois réaliser. Pour commencer je dois réaliser cette requête dans Access 2000. En fait cette requête sera basée sur l'extraction de données dans 5 tables différentes, comme de raison je voudrais tenter de faire une seule et unique requête pour récupérer les données voulues, si c'est faisable bien entendu.

    Pour faire une histoire courte, je dois gérer les appels d'une petite entreprise. Lorsqu'un client appel, la réceptionniste entre la description de l'appel. À ce moment j'enregistre donc dans une table APPEL le numéro du client, l'autre champ de cette table est un numéroauto qui est ma clé primaire. Par la suite dans une autre table APPEL_DESC j'enregistre le numéroauto de ma table APPEL correspondant, ainsi que l'heure et la date de l'appel et le numéro d'employé à qui est destiné l'appel. Voici donc les tables et les champs que je dois utilisé :

    APPEL
    id_appel clé
    id_client

    APPEL_DESC
    id_appel relié à ma table APPEL
    id_employe relié à ma table EMPLOYE
    date
    heure

    CLIENT
    numero clé
    nom

    CLIENT_ID
    id_client clé
    numero relié à ma table CLIENT (j'utilise cette table parce dans la table CLIENT le numero est basé sur le numéro de téléphone donc si le client change de numéro de teléphone je ne voudrais pas perdre les données de ce client)

    EMPLOYE
    id_employe
    nom

    Donc ce que je désire voir afficher par cette requête est le numéro du client (celui de la table CLIENT et non l'id de la table CLIENT_ID), le nom du client, la date et l'heure de l'appel ainsi que le nom de l'employé à qui est destiné cette appel. De plus puisque qu'après a répondu à cet appel celui-ci se retrouve dans la table APPEL_RETOUR, je dois m'assurer que id_appel n'est pas dans cette table.

    J'ai tenté désespérement de réaliser cette requête, mais je n'arrive pas à trouver la bonne solution. Alors si quelqu'un parmi vous pourrait m'indiquer la marche à suivre, ça me serait d'un grand secours car je vais avoir plusieurs requêtes du même genre à réaliser.

    Merci d'avance pour vos savantes réponses.

    @ +
    Denis

  2. #2
    Membre éclairé

    Développeur Web
    Inscrit en
    Mars 2002
    Messages
    412
    Détails du profil
    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2002
    Messages : 412
    Points : 657
    Points
    657
    Par défaut
    Bonjour, ta table CLIENT_ID est en trop.

    Il faut que tu mettes la colonne id_client dans la table Client. Et la clé du Client doit être id_client et pas son numéro.

    De plus, ça ne changera rien à ton problème mais la table APPEL_DESC n'a pas de raison d'être. Ses colonnes peuvent être incluses dans APPEL. Si pour des raisons techniques tu souhaites enregistrer les infos en deux fois, alors la première fois tu fais un INSERT et la deuxième un UPDATE.

    Ce qui te donnera :

    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
    APPEL
    id_appel clé
    id_client relié à la table CLIENT
    id_employe relié à ma table EMPLOYE
    date
    heure
     
    CLIENT
    id_client clé
    numero
    nom
     
    EMPLOYE
    id_employe clé
    nom
    Avec ça tu pourras faire ta requête. N'hésite pas à redemander si tu bloques sur la requête.

    Bon courage

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Merci laffeuxthomas pour ta réponse, mais à moins que tu veuilles contredire les dires de l'expert en place Fréderic. Je n'ai pas de table superflu dans ma BDD. Ma BDD est le plus normalisé possible, tel que Frédéric l'explique sur son site et qu'on retrouve sur ce forum. Rechercher l'id d'un client dans une table qui contient seulement deux champ est beaucoup plus rapide que de chercher ce même client dans une table qui contient 20 champs différents dont la plupart en texte, ce qui occupe beaucoup plus d'octets.

    Donc je cherche toujours la façon de faire ma requête du mieux possible en gardant mes tables dans leur état actuel. En passant je n'ai pas écrit tous les champs des tables que j'ai nommé, car certaines en contiennent plusieurs autres. J'ai simplement énuméré les champs nécessaires pour obtenir le résultat voulu.

    Merci à l'avance

    @+
    Denis

  4. #4
    Membre éclairé

    Développeur Web
    Inscrit en
    Mars 2002
    Messages
    412
    Détails du profil
    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2002
    Messages : 412
    Points : 657
    Points
    657
    Par défaut
    Est-ce que il peut y avoir :

    => Plusieurs lignes dans CLIENT_ID qui référencent une même ligne dans CLIENT ?
    => Plusieurs lignes dans APPEL_DESC qui référencent une même ligne dans APPEL ?

    A chaque fois que la réponse est non, c'est que tu as une table en trop. Et surtout, dupliquer le numéro du client c'est difficile d'appeler ça normalisé. Mais tu peux aussi attendre que SQLpro passe par là si tu préfères.

    C'est franchement une bétise, mais bon si tu veux ta requête...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT CLIENT.numero, CLIENT.nom, APPEL_DESC.date, APPEL_DESC.heure, EMPLOYE.nom
    FROM APPEL 
      INNER JOIN CLIENT_ID ON CLIENT_ID.id_client = APPEL.id_client
      INNER JOIN CLIENT ON CLIENT_ID.numero = CLIENT.numero
      INNER JOIN APPEL_DESC ON APPEL_DESC.id_appel = APPEL.id_appel
      INNER JOIN EMPLOYE ON APPEL_DESC.id_employe = EMPLOYE.id_employe;
    Voilà, sous Access si tu passe par l'éditeur visuel de requêtes, il faut te mettre en mode SQL.

    Si tu as des clefs étrangères qui peuvent contenir null (des liens qui peuvent être indéfinis) il faut remplacer les 'INNER' qui correspondent par des 'LEFT'.

  5. #5
    Membre éclairé

    Développeur Web
    Inscrit en
    Mars 2002
    Messages
    412
    Détails du profil
    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2002
    Messages : 412
    Points : 657
    Points
    657
    Par défaut
    J'avais pas vu la vérif de APPEL_RETOUR, avec la vérif :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    SELECT CLIENT.numero, CLIENT.nom, APPEL_DESC.date, APPEL_DESC.heure, EMPLOYE.nom
    FROM APPEL 
      INNER JOIN CLIENT_ID ON CLIENT_ID.id_client = APPEL.id_client
      INNER JOIN CLIENT ON CLIENT_ID.numero = CLIENT.numero
      INNER JOIN APPEL_DESC ON APPEL_DESC.id_appel = APPEL.id_appel
      INNER JOIN EMPLOYE ON APPEL_DESC.id_employe = EMPLOYE.id_employe
      LEFT JOIN APPEL_RETOUR ON APPEL.id_appel = APPEL_RETOUR.id_appel
    WHERE APPEL_RETOUR.id_appel is null;
    Mais corrige ton schéma par pitié !

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Merci pour ta réponse l'affreuxthomas. En fait ce que je tentais de faire depuis le début ressemblait beaucoup à ce que tu viens de me donner. Quand j'écris cette requête dans Access, j'obtiens toujours une erreur de syntaxe, disant qu'il y a un opérateur absent. C'est ce qui se produisait lorsque je tentais de le faire avec mes essais et il se reproduit encore la même chose avec la requête que tu viens de me fournir.

    Si j'écris une requête avec seulement un INNER JOIN à l'intérieur, il n'y a pas de problème. Mais aussitôt que j'ajoute un second INNER JOIN, il semble qu'Access n'aime pas.

    Par exemple si je fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT * FROM MaTable1
    INNER JOIN MaTable2 ON Matable2.MonChamp = MaTable1.MonChamp
    Dans ce cas je n'ai pas de problème, par contre si je tente de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    SELECT * FROM MaTable1
    INNER JOIN MaTable2 ON Matable2.MonChamp1 = MaTable1.MonChamp1
    INNER JOIN MaTable3 ON MaTable3.MonChamp2 = MaTable2.MonChamp2
    Alors là j'obtiens «ERREUR de syntaxe(opérateur absent) dans l'expression 'MaTable2.MonChamp1 = MaTable1.MonChamp1 INNER JOIN MaTable3 ON MaTable3.MonChamp2 = MaTable2.MonChamp2'»

    J'ai bien essayé de séparer chacun par des parenthèses ou encore des virgules, mais rien à faire il refuse de considérer le second INNER JOIN sans me sortir un message d'erreur. Donc de quelle façon arrive-t-on à créer une requête ayant plus d'une jointure dans Access. Pour le moment la seule façon que je parviens à obtenir le résultat voulu c'est avec une requête SELECT avec toutes les conditions dans la Clause WHERE, ce qui est loin d'être l'idéal.

    Merci encore à l'avance pour vos solutions

    @ +
    Denis

  7. #7
    Membre actif

    Profil pro
    Inscrit en
    Juin 2003
    Messages
    209
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2003
    Messages : 209
    Points : 249
    Points
    249
    Par défaut
    Salut,

    Je me permet d'essayer de te donner une réponse à ta question... enfin, si j'ai bien compris ton problème.

    Problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SELECT * FROM MaTable1 INNER JOIN MaTable2 ON Matable2.MonChamp1 = MaTable1.MonChamp1 
    INNER JOIN MaTable3 ON MaTable3.MonChamp2 = MaTable2.MonChamp2
    il me semble que dans ta requête, il manque des parenthèses... si tu fais un exemple, le wizard d'Access te donne qqch comme cela:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    SELECT *
    FROM (maTable1 INNER JOIN maTable2 ON maTable1.id = maTable2.id) INNER JOIN maTable3 ON maTable2.id = maTable3.id;
    le inner join n'est rien qu'une équijointure... donc sous Access tu peux également écrire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    SELECT * 
    FROM MaTable1, maTable2, maTable3
    WHERE Matable2.MonChamp1 = MaTable1.MonChamp1 
    AND MaTable3.MonChamp2 = MaTable2.MonChamp2
    De plus je me permets de faire un commentaire sur:
    tel que Frédéric l'explique sur son site et qu'on retrouve sur ce forum. Rechercher l'id d'un client dans une table qui contient seulement deux champ est beaucoup plus rapide que de chercher ce même client dans une table qui contient 20 champs différents dont la plupart en texte, ce qui occupe beaucoup plus d'octets.
    Il est vrai que si tu as une table avec bcp d'attributs, cela risque d'être plus lent. Mais il faut également savoir combien d'enregistrement tu auras dans ta future bd. Si le nombre dépasse pas 10000 je pense qu'il est inutile de créer des tables supplémentaires juste pour l'optimisation (je suis d'accord avec laffreuxthomas). J'ai jamais vu qqun qui créer des tables supplémentaire juste pour des questions de performance. Normalement les indexes sont là pour cela. Créer un indexe sur ton id_client et désormais le nombre d'attribut n'influence pas sur la performance.

    Dans chaque projet, je préconise de faire vraiment attention aux besoins. Pourquoi créer une bd qui peut être performante pour une multinational alors que tu travailles dans une PME.

    Bon courage et A+

  8. #8
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Merci Bouboubou

    C'était effectivement qu'un petit jeu de parenthèses que je ne disposais pas comme il faut. Maintenant tout fonctionne à merveille.

    Pour ce qui est de la différence entre une requête avec les équijointures et une requête avec une clause WHERE comme tu as donné en exemple, encore pour une question de performance, il me semblait que celle avec des équijointures est plus rapide. Peut-être ai-je mal compris la leçon ? Enfin bref, j'ai essayé les deux et comme de raison j'obtiens le même résultat.

    Pour ce qui des tables en trop, je concède que ma table CLIENT_ID était de trop. C'était effectivement un peu tirer par les cheveux pour celle-là. Par contre, et là ce serait trop long d'expliquer tout le processus de la gestion des appels dans le programme que je suis en train de faire, ma table APPEL n'est pas de trop, même si je sais très bien que j'aurais effectivement pu mettre l'id de l'appel dans ma table APPEL_DESC comme me l'indiquait l'affreuxthomas. Ma table APPEL me servira en fait à m'éviter un nombre incalculable de requête et de ligne de code à l'intérieur même de mon programme. Je dois effectuer un suivi pour chaque appel selon leur état, ce qui fait que l'appel peut très bien se retrouver dans 5 autres tables différentes selon son état. Alors pour m'éviter d'avoir à parcourir toutes les tables pour retracer l'histoirique d'un appel, j'utilise une autre table contenant l'histoirique de chaque appel qui réfère justement à chacune de mes tables. Je m'évite ainsi d'avoir à parcourir chaque table pour rechercher les dates et l'heure de chaque appel afin de les comparer l'un à l'autre pour trouver le plus récent par exemple. De cette façon je fais beaucoup moins de manipulation de requête et je me sauve je ne sais combien de ligne de code, et le plus beau c'est ce que je vais sûrement améliorer de façon considérable les performances de mon programme.

    Merci encore de vos conseils

    @ +
    Denis

  9. #9
    Membre actif

    Profil pro
    Inscrit en
    Juin 2003
    Messages
    209
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2003
    Messages : 209
    Points : 249
    Points
    249
    Par défaut
    Pour ce qui est de la différence entre une requête avec les équijointures et une requête avec une clause WHERE comme tu as donné en exemple, encore pour une question de performance, il me semblait que celle avec des équijointures est plus rapide. Peut-être ai-je mal compris la leçon ? Enfin bref, j'ai essayé les deux et comme de raison j'obtiens le même résultat.
    Je pense que cela n'était pas clair dans mon premier mail, mais il n'y a pas de différence entre les INNER JOIN et l'équijointure avec la clause WHERE. Le SQL 92 ne supporte pas les INNER JOIN et on peut utiliser que la clause WHERE. C'est juste une question de normalisation et du SGBD que tu utilises.

    Je suis content que tu as pu résoudre ton problème.

    A+

  10. #10
    Membre éclairé

    Développeur Web
    Inscrit en
    Mars 2002
    Messages
    412
    Détails du profil
    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2002
    Messages : 412
    Points : 657
    Points
    657
    Par défaut
    Remarque : il faut utiliser dès qu'on le peut un 'INNER JOIN' plutôt qu'un critère dans la clause Where. Et sous Access c'est implémenté depuis au moins 6 ans.

  11. #11
    Membre éclairé

    Développeur Web
    Inscrit en
    Mars 2002
    Messages
    412
    Détails du profil
    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2002
    Messages : 412
    Points : 657
    Points
    657
    Par défaut
    Citation Envoyé par Bouboubou
    Le SQL 92 ne supporte pas les INNER JOIN et on peut utiliser que la clause WHERE
    Euh non c'est l'inverse

  12. #12
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Merci de la précision l'affreuxthomas,

    Je vais tenter d'utiliser le plus souvent possible les jointures plutôt que la clause WHERE. Mais tu pourrais me dire la véritable raison. Est-ce bien pour une question de performance ? Si oui pour quelle raison

    Merci

    @ +
    Denis

  13. #13
    Membre éclairé

    Développeur Web
    Inscrit en
    Mars 2002
    Messages
    412
    Détails du profil
    Informations professionnelles :
    Activité : Développeur Web

    Informations forums :
    Inscription : Mars 2002
    Messages : 412
    Points : 657
    Points
    657
    Par défaut
    La véritable raison c'est que c'est la norme. Tout le monde suit la norme, c'est pratique parce que c'est plus facile de reprendre le travail d'un autre.

    Accessoirement, puisque tout le monde suit le standard, les éditeurs de SGBD optimisent plutôt la manière de faire standard.

    Il ne faut pas trop se focaliser sur l'optimisation.

    Un bon projet, c'est un projet qui :

    1) Répond aux besoins de l'utilisateur
    2) A été réalisé dans les temps
    3) Est facile à relire par d'autres informaticiens, est bien documenté, est ouvert aux futurs fonctionnalités etc..

    L'optimisation on s'en occupe donc à condition que la lenteur du logiciel soit génante pour l'utilisateur. Donc sur la plupart des projets d'IHM de base de données, on regarde ça à postériori.

    A part dans ce cas-là, l'optimisation en temps que telle n'est pas un critère pour évaluer un projet.

    Tout ceci pour dire qu'il faut utiliser les 'INNER JOIN' pour faire du code standard car le standard c'est plus lisible. L'optimisation si ton utilisateur s'en fiche, tu t'en fiches.

  14. #14
    Futur Membre du Club
    Profil pro
    Inscrit en
    Novembre 2003
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Novembre 2003
    Messages : 12
    Points : 8
    Points
    8
    Par défaut
    Merci encore une fois l'affreuxthomas pour ces conseils. J'en prend bonne note.

    @ +
    Denis

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

Discussions similaires

  1. [SQL] Requête complexe sur plusieurs tables
    Par BFH dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 21/09/2007, 16h21
  2. requêtes sql sur plusieurs tables
    Par zahiton dans le forum Langage SQL
    Réponses: 4
    Dernier message: 25/11/2005, 10h59
  3. [SQL] requêtes SQL sur plusieurs tables
    Par zahiton dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 24/11/2005, 16h32
  4. Encore une requête complexe sur plusieurs tables
    Par DenPro dans le forum Langage SQL
    Réponses: 5
    Dernier message: 09/12/2003, 19h05
  5. A propos d'une requête SQL sur plusieurs tables...
    Par ylebihan dans le forum Langage SQL
    Réponses: 2
    Dernier message: 14/09/2003, 16h26

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