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 :

Doublons dans les résultats d'une jointure


Sujet :

Requêtes MySQL

  1. #1
    Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2005
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juin 2005
    Messages : 70
    Points : 55
    Points
    55
    Par défaut Doublons dans les résultats d'une jointure
    Bonjour à tous !

    J'ai 2 tables (je simplifie) :
    ‘t_auteurs‘ avec 3 champs : ID, nom_aut, prenom_aut
    't_adresses' avec 6 champs : ID, adr1, adr2, ville, pays, id_auteur

    A noter : je peux avoir N adresses par auteur.

    Je veux AFFICHER la liste de TOUS les auteurs, SANS DOUBLON, avec pour chacun l'ID de la PREMIERE adresse rencontrée.
    "PREMIERE" signifie : je me fous de laquelle, c'est la première extraite par le Moteur MySQL.
    L'important pour moi est de ne pas récupérer 10 lignes "Auteur MARCEL" sous prétexte que celui-ci dispose de 10 adresses dans la table ‘t_adresses‘.

    Si je fais un simple "LEFT JOIN", genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        SELECT `AU`.`ID`,`AU`.`nom_aut`,`AU`.`prenom_aut`,`AD`.`ID` AS ID_adress
        FROM `t_autres` `AU` 
        LEFT JOIN `t_adresses` `AD` ON (`AD`.`id_auteur` = `AU`.`ID`)
    ...j'obtiens (c'est un jeu de test) :

    Nom : mysql.jpg
Affichages : 555
Taille : 11,4 Ko

    AGUSTA ayant 2 adresses, je le récupère deux fois - Je ne veux que le premier rencontré.
    Est-il possible de faire ça purement en MySQL (...sachant que, ok, je peux toujours éliminer les doublons dans ma loop dl'affichage) ?

    Merci à vous !

  2. #2
    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,
    Tu peux ajouter un MIN (ou un MAX) su l'ID de l'adresse, et regrouper sur les autres colonnes avec un GROUP BY.

    Tatayo.

  3. #3
    Membre du Club
    Homme Profil pro
    Retraité
    Inscrit en
    Juin 2005
    Messages
    70
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 76
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Juin 2005
    Messages : 70
    Points : 55
    Points
    55
    Par défaut Ca marche
    Merci beaucoup ! Je m'étais finalement résigné à traiter ça en aval, au stade de l'affichage...

  4. #4
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut à tous.

    @ tatayo : c'est très bien d'indiquer la solution au problème de "PureEsprit", mais un exemple serait le bien venu.
    Surtout que dans ce cas de figure, il n'est pas nécessaire d'utiliser la fonction "min" pour récupérer la première adresse, si elle existe.

    Allez, je m'y colle.

    Plusieurs remarques :

    1) ne mettez pas de 's' pour indiquer le nom de vos tables.
    Nous savons que chaque table va contenir plusieurs "auteurs" et plusieurs "adresses'.
    Il est aussi inutile de préfixer vos tables par "t_", sauf si par ailleurs, vous utilisez des view.

    2) il est inutile d'utiliser un identifiant autre que celui de la table "auteur" pour identifier les adresses qui sont liés à un auteur.
    Il suffit de reprendre le même identifiant que celui que vous utilisez dans la table "auteur".

    3) pour identifier la multiplicité des adresses, pourquoi ne pas utiliser une colonne rang ?
    En fait, cette solution vous permet de faire l'économie de la fonction "min", car si une adresse existe, elle aura nécessairement le rang 1.

    4) afin de ne pas avoir de problème d'intégrité, vous devez utiliser les clef étrangère.

    Voici la solution que je propose :
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    --------------
    SET AUTOCOMMIT = 0
    --------------
     
    --------------
    START TRANSACTION
    --------------
     
    --------------
    DROP DATABASE IF EXISTS `base`
    --------------
     
    --------------
    CREATE DATABASE `base`
        DEFAULT CHARACTER SET `latin1`
        DEFAULT COLLATE       `latin1_general_ci`
    --------------
     
    --------------
    DROP TABLE IF EXISTS `auteur`
    --------------
     
    --------------
    CREATE TABLE `auteur`
    ( `id`      integer  unsigned  NOT NULL auto_increment primary key,
      `nom`     varchar(255)       NOT NULL,
      `prenom`  varchar(255)       NOT NULL
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `auteur` (`id`,`nom`,`prenom`) VALUES
    (15, 'Mailly', 'Mireille'),
    (19, 'Zanier', 'Luisa'),
    (27, 'Agusta', 'Pierre')
    --------------
     
    --------------
    select * from `auteur`
    --------------
     
    +----+--------+----------+
    | id | nom    | prenom   |
    +----+--------+----------+
    | 15 | Mailly | Mireille |
    | 19 | Zanier | Luisa    |
    | 27 | Agusta | Pierre   |
    +----+--------+----------+
    --------------
    DROP TABLE IF EXISTS `adresse`
    --------------
     
    --------------
    CREATE TABLE `adresse`
    ( `id`      integer unsigned  NOT NULL,
      `rang`    integer unsigned  NOT NULL,
      `ligne`   varchar(255)      NOT NULL,
      `postal`  integer unsigned  NOT NULL,
      `ville`   varchar(255)      NOT NULL,
      primary key (`id`,`rang`),
      CONSTRAINT `FK_AUTEUR` FOREIGN KEY (`id`) REFERENCES `auteur` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    --------------
     
    --------------
    INSERT INTO `adresse` (`id`,`rang`,`ligne`,`postal`,`ville`) VALUES
    (15, 1, 'x x x x x x x', 75014, 'Paris'),
    (15, 2, 'y y y y y y y', 69000, 'Lyon'),
    (15, 3, 'z z z z z z z', 13000, 'Marseille'),
    (27, 1, '- - - - - - -', 06400, 'Cannes'),
    (27, 2, '- - - - - - -', 06000, 'Nice'),
    (27, 3, '- - - - - - -', 06500, 'Menton')
    --------------
     
    --------------
    select * from `adresse`
    --------------
     
    +----+------+---------------+--------+-----------+
    | id | rang | ligne         | postal | ville     |
    +----+------+---------------+--------+-----------+
    | 15 |    1 | x x x x x x x |  75014 | Paris     |
    | 15 |    2 | y y y y y y y |  69000 | Lyon      |
    | 15 |    3 | z z z z z z z |  13000 | Marseille |
    | 27 |    1 | - - - - - - - |   6400 | Cannes    |
    | 27 |    2 | - - - - - - - |   6000 | Nice      |
    | 27 |    3 | - - - - - - - |   6500 | Menton    |
    +----+------+---------------+--------+-----------+
    --------------
    select           t1.nom,
                     t1.prenom,
                     t2.ligne,
                     t2.postal,
                     t2.ville
     
               from  `auteur`  as t1
     
    left outer join  `adresse` as t2
                 on  t2.id = t1.id
                and  t2.rang = 1
    --------------
     
    +--------+----------+---------------+--------+--------+
    | nom    | prenom   | ligne         | postal | ville  |
    +--------+----------+---------------+--------+--------+
    | Mailly | Mireille | x x x x x x x |  75014 | Paris  |
    | Zanier | Luisa    | NULL          |   NULL | NULL   |
    | Agusta | Pierre   | - - - - - - - |   6400 | Cannes |
    +--------+----------+---------------+--------+--------+
    --------------
    COMMIT
    --------------
     
    --------------
    SET AUTOCOMMIT = 1
    --------------
     
    Appuyez sur une touche pour continuer...
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  5. #5
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par puresprit Voir le message
    J'ai 2 tables (je simplifie) :
    ‘t_auteurs‘ avec 3 champs : ID, nom_aut, prenom_aut
    't_adresses' avec 6 champs : ID, adr1, adr2, ville, pays, id_auteur
    Dans une base de données, les champs n'existent pas. On parle de colonnes



    Citation Envoyé par puresprit Voir le message
    A noter : je peux avoir N adresses par auteur.
    C'est tout à fait classique, mais il faut en ce cas typer les adresses : adresse de résidence principale, de résidence secondaire, de correspondance, de livraison...
    Et par conséquent une table des types adresses fait son apparition, ainsi qu'une clef étrangère dans la table adresse qui pointe sur la clef primaire de la table type_adresse



    Citation Envoyé par Artemus24 Voir le message
    Salut à tous.
    Il est aussi inutile de préfixer vos tables par "t_", sauf si par ailleurs, vous utilisez des view.
    En entreprise, la codification des objets est souvent normée et laisse peu de latitude de choix
    En cas d'usage privé, certains utilisent un préfixe différent selon que la table est issue d'une Entité-Type du MCD (exemple TE) ou d'une relation (TR)
    Dans tous les cas il est préférable d'éviter les caractères spéciaux (accents, diacritiques) et les mots réservés dans tous les noms d'objets de la base de données (tables, vues, colonnes, triggers...)



    Citation Envoyé par Artemus24 Voir le message
    2) il est inutile d'utiliser un identifiant autre que celui de la table "auteur" pour identifier les adresses qui sont liés à un auteur.
    Il suffit de reprendre le même identifiant que celui que vous utilisez dans la table "auteur".
    Plus précisément, il s'agit d'identifier l'adresse relativement à l'auteur. C'est à dire que l'identifiant de l'adresse est composé de id_auteur + id_adresse
    On a donc bien un identifiant autre, mais il se combine à celui de l'auteur. C'est ce qu'on appelle l'identification relative.
    Au niveau conceptuel, l'adresse est considérée comme une entité-type faible (weak entity). L'adresse n'existe que si l'auteur existe, si l'auteur disparait, ses adresses aussi.



    Citation Envoyé par Artemus24 Voir le message
    3) pour identifier la multiplicité des adresses, pourquoi ne pas utiliser une colonne rang ?
    En fait, cette solution vous permet de faire l'économie de la fonction "min", car si une adresse existe, elle aura nécessairement le rang 1.
    Qui dit rang, dit classement selon un critère.
    C'est pourquoi, je pense que le le terme de "rang" est inadéquat pour cet usage. Il porte confusion avec le classement que l'on peut obtenir via les fonctions OLAP rank() et dense_rank() (à condition d'avoir la version 8 de MySQL)
    Non, ici, comme expliqué précédemment, il s'agit d'un cas classique d'identification relative. On a donc une PK composée



    Citation Envoyé par Artemus24 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    CREATE TABLE `adresse`
    ( `id`      integer unsigned  NOT NULL,
      `rang`    integer unsigned  NOT NULL,
      `ligne`   varchar(255)      NOT NULL,
      `postal`  integer unsigned  NOT NULL,
      `ville`   varchar(255)      NOT NULL,
      primary key (`id`,`rang`),
      CONSTRAINT `FK_AUTEUR` FOREIGN KEY (`id`) REFERENCES `auteur` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
    ) ENGINE=InnoDB
      DEFAULT CHARSET=`latin1` COLLATE=`latin1_general_ci`
      ROW_FORMAT=COMPRESSED
    Les adresses françaises et étrangères sont normées.
    En France il faut 6 lignes de 38 caractères.
    Par ailleurs, le code postal et la ville doivent être externalisés, ils ne dépendent pas fonctionnellement de l'adresse, les stocker à ce niveau est une redondance, avec tous les risques que cela comporte : orthographes divergentes, CP incohérents avec la commune...
    Enfin, un code postal doit être stocké dans du char(5), pas dans un type numérique

  6. #6
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 381
    Points : 19 065
    Points
    19 065
    Par défaut
    Salut Escartefigue.

    Merci pour vos remarques.

    J'ai fait au plus simple, afin de ne pas alourdir le sujet en déviant sur la modélisation des adresses.
    J'ai simplement répondu à la question posée :
    Citation Envoyé par Puresprit
    AGUSTA ayant 2 adresses, je le récupère deux fois - Je ne veux que le premier rencontré.
    Est-il possible de faire ça purement en MySQL (...sachant que, ok, je peux toujours éliminer les doublons dans ma loop à l'affichage) ?
    C'est-à-dire supprimer les doublons !

    Voici mes remarques :

    Citation Envoyé par Escartefigue
    En entreprise, la codification des objets est souvent normée et laisse peu de latitude de choix
    Je le sais. Je ne suis pas contre un préfixe si cela permet de catégoriser la modélisation.
    Dans un autre sujet, j'ai vu des noms à rallonge, comme celui-ci : "ps_wk_mp_seller_transaction_history".
    Cet exemple me dérange car le nom est trop long et trop compliqué à lire.

    Citation Envoyé par Escartefigue
    C'est pourquoi, je pense que le terme de "rang" est inadéquat pour cet usage.
    J'avais à l'esprit un numéro séquentiel allant de 1 à N. J'ai automatiquement pensé au "rang".
    Comme à mon habitude, je ne trouve pas toujours les mots justes.

    Citation Envoyé par Escartefigue
    Enfin, un code postal doit être stocké dans du char(5), pas dans un type numérique
    Ne confondez pas le département, qui pour la Corse est "2A" et "2B" avec le code postal qui commence toujours par "20".
    En fait, le code postal utilise l'ancienne numérotation des départements qui étaient alors numériques.
    Est-il justifié pour la France, d'utiliser un type char(05) ?

    Je ne vais pas m'étaler sur la modélisation car ce n'est pas le but de ce sujet.
    En ce qui concerne la modélisation des adresses, on peut se référer à l'exercice de SQLPRO :
    --> https://blog.developpez.com/exercice..._d_une_adresse
    ainsi qu'aux normes :
    --> https://sqlpro.developpez.com/cours/normes/#L3

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  7. #7
    Modérateur
    Avatar de escartefigue
    Homme Profil pro
    bourreau
    Inscrit en
    Mars 2010
    Messages
    10 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loir et Cher (Centre)

    Informations professionnelles :
    Activité : bourreau
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2010
    Messages : 10 136
    Points : 38 561
    Points
    38 561
    Billets dans le blog
    9
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    Dans un autre sujet, j'ai vu des noms à rallonge, comme celui-ci : "ps_wk_mp_seller_transaction_history".
    Cet exemple me dérange car le nom est trop long et trop compliqué à lire.
    Tout à fait d'accord, c'est pénible à l'usage et n'apporte rien.
    Une codification bien faite permet d'éviter ces noms à rallonge.

    Citation Envoyé par Artemus24 Voir le message
    Ne confondez pas le département, qui pour la Corse est "2A" et "2B" avec le code postal qui commence toujours par "20".
    En fait, le code postal utilise l'ancienne numérotation des départements qui étaient alors numériques.
    Est-il justifié pour la France, d'utiliser un type char(05) ?
    Les codes postaux peuvent commencer par un zéro qu'il convient de conserver, un type char permet de restituer facilement les 5 caractères sans nécessité de mise en forme
    D'une façon générale les codes dont le contenu est numérique mais qui n'ont pas vocation à faire l'objet de calculs sont stockés dans des colonnes de type char.

    Toute nomenclature externe est susceptible d'être modifiée. L'exemple des codes départements en est une très bonne illustration : quand la corse a été divisée en 2, l'apparition des codes "2A" et "2B" à la place du "20" a posé de gros problèmes dans les S.I. qui avaient justement commis l'erreur d'utiliser une colonne de type numérique.

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

Discussions similaires

  1. Une requête qui donne des doublons dans les résultats
    Par HDR_16 dans le forum Langage SQL
    Réponses: 7
    Dernier message: 16/04/2014, 18h51
  2. Mots en gras dans les résultats d'une recherche
    Par Freedolphin dans le forum Langage
    Réponses: 9
    Dernier message: 25/11/2011, 19h07
  3. Ne pas obtenir de doublons dans les résultats.
    Par Premium dans le forum MS SQL Server
    Réponses: 6
    Dernier message: 26/06/2007, 14h58
  4. Réponses: 12
    Dernier message: 23/05/2007, 10h37

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