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 :

Joindre la dernière occurrence d'une table


Sujet :

Langage SQL

  1. #1
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut Joindre la dernière occurrence d'une table
    Bonjour à tous,

    j'ai une table ps_address contenant différentes adresses et la table ps_customer contenant différents clients. J'aimerais joindre au customer la dernière adresse qu'il a créée.

    j'essaie de faire l'équivalent de ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    LEFT JOIN 
            (SELECT * FROM ps_address) as A 
    		ON A.id_customer=C.id_customer AND A.id_address IN (SELECT MAX(id_address) FROM ps_address A GROUP BY id_customer)
    mais vu le nombre d'enregistrements, c'est extrêmement lent, forcément.

    Avez-vous une idée de comment faire ?

    Merci d'avance

  2. #2
    Membre émérite Avatar de lola06
    Femme Profil pro
    Consultante en Business Intelligence
    Inscrit en
    Avril 2007
    Messages
    1 316
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultante en Business Intelligence
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 316
    Points : 2 520
    Points
    2 520
    Par défaut
    Il est possible de faire une jointure, à vérifier si c'est vraiment mieux :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    LEFT JOIN (
        SELECT A1.id_customer, A1.id_adress
        FROM ps_address A1    
        JOIN (
           SELECT id_customer, MAX(id_address) id_address
           FROM ps_address
           GROUP BY id_customer
        ) A2
        ON A1.id_customer = A2.id_customer
        AND A1.id_address= A2.id_address
    ) as A 
    ON A.id_customer=C.id_customer
    ~ Lola ~

  3. #3
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    ça ne marche pas mieux malheureusement, ça mouline..

  4. #4
    Membre émérite Avatar de lola06
    Femme Profil pro
    Consultante en Business Intelligence
    Inscrit en
    Avril 2007
    Messages
    1 316
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultante en Business Intelligence
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 316
    Points : 2 520
    Points
    2 520
    Par défaut
    Il serait peut-être intéressant de voir toute la requête à optimiser. Et les index.

    De plus au bout d'un moment si vraiment il y a beaucoup d'enregistrement il faut bien que ça réfléchisse.
    ~ Lola ~

  5. #5
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    j'ai essayé ça sans que ça marche mieux aussi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    INNER JOIN ps_address A ON A.id_customer=C.id_customer AND A.id_address IN (SELECT MAX(id_address) FROM ps_address GROUP BY id_customer)
    EDIT : (je précise que je n'ai pas d'autre jointure ou quoique ce soit d'autre qui puisse faire ramer ; avant ça, ya juste un SELECT * FROM ps_customer C)

  6. #6
    Membre émérite Avatar de lola06
    Femme Profil pro
    Consultante en Business Intelligence
    Inscrit en
    Avril 2007
    Messages
    1 316
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultante en Business Intelligence
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 316
    Points : 2 520
    Points
    2 520
    Par défaut
    Pourriez-vous mettre l'explain plan de la requête ?
    ~ Lola ~

  7. #7
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par lola06 Voir le message
    Il serait peut-être intéressant de voir toute la requête à optimiser. Et les index.

    De plus au bout d'un moment si vraiment il y a beaucoup d'enregistrement il faut bien que ça réfléchisse.
    Pas de souci d'index, voici ce que dit le EXPLAIN :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    +----+--------------------+------------+-------+----------------------------+------------------+---------+-----------------------+-------+-------------+
    | id | select_type        | table      | type  | possible_keys              | key              | key_len | ref                   | rows  | Extra       |
    +----+--------------------+------------+-------+----------------------------+------------------+---------+-----------------------+-------+-------------+
    |  1 | PRIMARY            | C          | ALL   | PRIMARY,id_customer_passwd | NULL             | NULL    | NULL                  | {DESDIZAINESDEMILLIERS} |             |
    |  1 | PRIMARY            | A          | ref   | address_customer           | address_customer | 4       | xx.C.id_customer      |     1 | Using where |
    |  2 | DEPENDENT SUBQUERY | ps_address | index | NULL                       | address_customer | 4       | NULL                  |     1 | Using index |
    +----+--------------------+------------+-------+----------------------------+------------------+---------+-----------------------+-------+-------------+
    Merci pour ton aide,

  8. #8
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 768
    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 768
    Points : 52 577
    Points
    52 577
    Billets dans le blog
    5
    Par défaut
    De toutes façon se baser sur un ID pour trouver le dernier est parfaitement stupide. Rien ne garantie que ce soit bien la dernière adresse !
    En effet, on peut toujours forcer un auto incrément ou encore décrémenter....

    La seule solution viable consiste à rajouter une colonne DATE dans votre table, avec la date de validité de l'adresse.

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

  9. #9
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par SQLpro Voir le message
    De toutes façon se baser sur un ID pour trouver le dernier est parfaitement stupide. Rien ne garantie que ce soit bien la dernière adresse !
    En effet, on peut toujours forcer un auto incrément ou encore décrémenter....

    La seule solution viable consiste à rajouter une colonne DATE dans votre table, avec la date de validité de l'adresse.

    A +
    Tout d'abord, merci pour la réponse, quoiqu'un brin agressive pour un modérateur.

    D'un point de vue purement SGBD (quand on ne maîtrise pas ce qui peut arriver en face) c'est peut-être une hérésie, je ne sais pas .

    Dans notre système, le dernier ID est forcément la dernière insertion. Et on ne s'amuse pas à forcer un auto-incrément ou à décrémenter donc l'ID est le plus efficace à mon sens.

    Toutefois, si vous avez une solution, même avec la date, je suis preneur.

  10. #10
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    je précise que j'ai essayé ceci également et que ça ne marche pas mieux (même en laissant tourner 5mn)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     
    INNER JOIN ps_address A ON A.id_customer=C.id_customer 
    WHERE A.id_address IN (SELECT MAX(id_address) FROM ps_address GROUP BY id_customer)

  11. #11
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    j'ai l'impression que ceci marche beaucoup mieux !

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    INNER JOIN (SELECT * FROM ps_address ORDER BY id_address DESC) A ON A.id_customer=C.id_customer 
    GROUP BY C.id_customer
    ça me gêne de faire un GROUP BY à la fin mais c'est une solution extrêmement rapide ! (par contre : Using temporary; Using filesort)

    je précise que c'est pour une utilisation "deux/trois fois par jour" donc ce n'est pas grave mais si quelqu'un a besoin de solution pour une requête à utiliser au moins une fois par chargement de page, ça n'ira pas du coup

    je vais passer en "résolu" mais attention aux copieurs, la solution qui marche est à analyse de votre côté avec une option SQL_NO_CACHE et un EXPLAIN pour bien se rendre compte de la consommation de votre côté

    Merci à tous pour votre aide

  12. #12
    Membre émérite Avatar de lola06
    Femme Profil pro
    Consultante en Business Intelligence
    Inscrit en
    Avril 2007
    Messages
    1 316
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultante en Business Intelligence
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 316
    Points : 2 520
    Points
    2 520
    Par défaut
    Heu, je ne comprend pas trop to GROUP BY ici.

    Pourrais-tu mettre la requête entière ?
    ~ Lola ~

  13. #13
    Membre confirmé
    Homme Profil pro
    Inscrit en
    Juin 2011
    Messages
    445
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Juin 2011
    Messages : 445
    Points : 622
    Points
    622
    Par défaut
    Je suis un peu de l'avis de lola06, j'ai de gros doutes sur ta requête.

    Que donne ceci ? :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    INNER JOIN (SELECT id_customer,MAX(id_address) AS id_address FROM ps_address GROUP BY id_customer) T
    ON T.id_customer=C.id_customer 
    INNER JOIN ps_address 
    ON T.id_address=ps_address.id_address

  14. #14
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    la requête s'exécute assez rapidement mais ceci ne marche pas car j'ai besoin de tous les champs de l'adresse, pas seulement le MAX(id), ce qui complique les choses.

    Le Group By peut avoir une logique :
    1. je joins toutes les adresses au client (classées par ID DESC)
    2. je groupe par client pour n'avoir que la première


    La requête complète (modèle prestashop) qui fonctionne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    SELECT 
    *
     FROM ps_customer C
     
    INNER JOIN (SELECT * FROM ps_address ORDER BY id_address DESC) A ON A.id_customer=C.id_customer 
    GROUP BY C.id_customer

  15. #15
    Membre émérite Avatar de lola06
    Femme Profil pro
    Consultante en Business Intelligence
    Inscrit en
    Avril 2007
    Messages
    1 316
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultante en Business Intelligence
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 316
    Points : 2 520
    Points
    2 520
    Par défaut
    Citation Envoyé par Romalafrite Voir le message
    la requête s'exécute assez rapidement mais ceci ne marche pas car j'ai besoin de tous les champs de l'adresse, pas seulement le MAX(id), ce qui complique les choses.
    Sa requête est correcte, car si tu regardes attentivement il fait une autre jointure avec la table ps_address pour récupérer toutes les infos.

    Citation Envoyé par Romalafrite Voir le message
    Le Group By peut avoir une logique :
    1. je joins toutes les adresses au client (classées par ID DESC)
    2. je groupe par client pour n'avoir que la première


    Le group by doit être utilisé avec une fonction d'agrégation.
    Qu'est ce qui te garanti ici que c'est bien la première qui est prise ? Il n'y a aucun contrôle.

    Je viens de réagir un peu tard, mais plus haut tu nous as mis l'EXPLAIN, or ici c'est l'EXPLAIN PLAN de la requête qui est intéressant.
    ~ Lola ~

  16. #16
    Expert éminent sénior
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 198
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 198
    Points : 12 774
    Points
    12 774
    Par défaut
    Bonjour,
    J'ajoute mon grain de sel, avec une petite réflexion: la dernière adresse, c'est celle pour laquelle il n'en existe pas d'autre "après".
    Donc on peut aussi le faire avec une jointure:
    Code SQL : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    select customer.*
    from customer
    inner join adresse as a1 on a1.id_cust = customer.id
    left outer join adresse as a2 on a2.id_cust = customer.id and a2.id > a1.id
    where a2.id is null
    Bon, j'ai un peu appliqué l'hypothèse du monde clos, car je ne renvoie pas de client sans adresse, mais c'est pour l'idée.

    Tatayo.

  17. #17
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    Citation Envoyé par lola06 Voir le message
    Sa requête est correcte, car si tu regardes attentivement il fait une autre jointure avec la table ps_address pour récupérer toutes les infos.





    Le group by doit être utilisé avec une fonction d'agrégation.
    Qu'est ce qui te garanti ici que c'est bien la première qui est prise ? Il n'y a aucun contrôle.

    Je viens de réagir un peu tard, mais plus haut tu nous as mis l'EXPLAIN, or ici c'est l'EXPLAIN PLAN de la requête qui est intéressant.
    Le fonctionnement du group by est bien par défaut de prendre la première occurence ? ou je me trompe ? je n'ai mis aucune fonction d'agrégation et la requête fonctionne quand même en prenant la valeur que j'attendais.

  18. #18
    Membre émérite Avatar de lola06
    Femme Profil pro
    Consultante en Business Intelligence
    Inscrit en
    Avril 2007
    Messages
    1 316
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 37
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Consultante en Business Intelligence
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 316
    Points : 2 520
    Points
    2 520
    Par défaut
    Pour rappel un tutoriel sur l'utilisation du GROUP BY.

    Ce que tu décris est peut-être un effet de bord du GROUP BY, mais comme ça n'est pas le fonctionnement normalisé tu ne peux pas garantir tes résultats en l'utilisant de la sorte.
    ~ Lola ~

  19. #19
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 270
    Points : 163
    Points
    163
    Par défaut
    Effectivement, même la doc MySQL ne précise rien là-dessus..

    Merci pour votre aide en tout cas, très intéressante cette discussion !

  20. #20
    Expert éminent
    Avatar de StringBuilder
    Homme Profil pro
    Chef de projets
    Inscrit en
    Février 2010
    Messages
    4 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Février 2010
    Messages : 4 153
    Points : 7 403
    Points
    7 403
    Billets dans le blog
    1
    Par défaut
    Tatayo > Si je ne m'abuse, si tu remplaces le premier inner join par un left outer join, tu ramènes exactement ce que romalafrite cherche à faire.

    Et c'est à mon avis la requête la plus simple et la plus propre.
    On ne jouit bien que de ce qu’on partage.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [MySQL] Sélection des dernières lignes d'une table
    Par Civet dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 25/04/2007, 15h06
  2. dernière analyse d'une table
    Par big1 dans le forum Oracle
    Réponses: 7
    Dernier message: 04/09/2006, 17h31
  3. Réponses: 6
    Dernier message: 09/06/2006, 18h22
  4. [MySQL] lister les occurrences d'une table
    Par youyoule dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 07/09/2005, 20h37
  5. date de dernière modification d'une table ?
    Par NiBicUs dans le forum Requêtes
    Réponses: 3
    Dernier message: 17/12/2004, 18h11

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