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 avec relation N-N (entre 3 tables)


Sujet :

Langage SQL

  1. #1
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 10
    Points : 10
    Points
    10
    Par défaut Requête avec relation N-N (entre 3 tables)
    Bonjour,

    Je bosse avec SQL Server 2000.

    En fait, voilà le truc : je possède 3 tables :
    table Users : userid, username
    table Roles : roleid, rolename
    table UsersRoles : userid, roleid qui est née du fait qu'un utilisateur peut avoir plusieurs rôles et qu'un rôle peut être relié à plusieurs utilisateurs (relations N-N).

    Imaginons un peuplement comme le suivant :
    table Users :
    0 a
    1 b

    table Roles :
    0 finance
    1 tech
    2 validation

    table UsersRoles :
    0 0
    0 1
    1 1
    1 2

    Ce que je veux, c'est afficher dans un tableau cela :
    Nom utilisateur Roles de l'utilsateurs
    a finance, tech
    b tech, validation

    Et c'est donc là qu'intervient ma question : comment faire efficacement ??

    Car pour l'instant, je n'arrive a n'avoir que une requete qui renvoie autant de lignes que de roles (4 lignes dans ce cas là) et avec donc plusieurs lignes pour un même utilisateur.
    La solution est peut être de grouper les roles dans un même champ de résultat mais alors coment fait-on ??

    Merci beaucoup d'avance
    J'espère que j'ai été clair.
    Si ce n'est pas le cas, dites moi ce que vous voulez savoir de plus ?
      0  0

  2. #2
    Membre expert
    Avatar de TheLeadingEdge
    Inscrit en
    Mai 2005
    Messages
    1 199
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 1 199
    Points : 3 103
    Points
    3 103
    Par défaut
    Bonjour,

    Il faut recourir à quelques artifices. SQL 2 n'est pas vraiment adapté pour ce genre de mise en page. Malgré tout en faisant 1 recherche dans les anciens posts tu aurais vu que c'est 1 sujet qui a déjà été traité régulièrement ici.

    Voici 1 petite synthèse (probablement pas exhaustive mais déjà assez longue tout de même)

    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
    CREATE TABLE tligne 
    (
    lig VARCHAR (32) NOT NULL, 
    nom varchar (32) NOT NULL
    ); 
     
    CREATE TABLE tcolonne 
    (
    lig VARCHAR (32) NOT NULL, 
    col VARCHAR (32) NOT NULL, 
    val INTEGER NOT NULL
    );
     
    INSERT INTO tligne VALUES ('Ligne 1', 'Nom 1'); 
    INSERT INTO tligne VALUES ('Ligne 2', 'Nom 2');
    INSERT INTO tligne VALUES ('Ligne 3', 'Nom 3');
     
    INSERT INTO tcolonne VALUES ('Ligne 1', 'Colonne 1', 11); 
    INSERT INTO tcolonne VALUES ('Ligne 1', 'Colonne 2', 12); 
    INSERT INTO tcolonne VALUES ('Ligne 2', 'Colonne 3', 23); 
    INSERT INTO tcolonne VALUES ('Ligne 2', 'Colonne 2', 21); 
    INSERT INTO tcolonne VALUES ('Ligne 3', 'Colonne 1', 32); 
    INSERT INTO tcolonne VALUES ('Ligne 3', 'Colonne 3', 33);
    pour obtenir comme résultat :
    lig Colonne 1 Colonne 2
    -------------------------------- ----------- -----------
    Ligne 1 11 12
    Ligne 2 21 22
    Ligne 3 31 32
    --
    ---- A la façon de SQL-Pro
    ---- (Attention à l'auto-jointure. Il ne faut pas de 'trou' dans les valeurs)
    --
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT  T1.lig, 
    	T1.val AS "Colonne 1",
    	T2.val AS "Colonne 2"
    FROM tcolonne T1
    INNER JOIN tcolonne T2
    ON	T1.lig = T2.lig
    WHERE  	T1.col = 'Colonne 1'
    AND  	T2.col = 'Colonne 2'
    ORDER BY T1.lig;
    --
    ----
    --
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    SELECT  tligne.nom,
    	MAX(CASE WHEN col = 'Colonne 1' THEN val ELSE NULL END) as "Colonne 1", 
    	MAX(CASE WHEN col = 'Colonne 2' THEN val ELSE NULL END) as "Colonne 2",
    	MAX(CASE WHEN col = 'Colonne 3' THEN val ELSE NULL END) as "Colonne 3" 
    FROM   	tligne
    INNER JOIN tcolonne 
    ON 	tligne.lig = tcolonne.lig
    GROUP BY tligne.nom
    ORDER BY tligne.nom;
    --
    ---- Celle de 'Mr' Jo Celko
    --
    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
    SELECT	tligne.nom,
    	MAX(xtab.colonne1),
    	MAX(xtab.colonne2),
    	MAX(xtab.colonne3)
    FROM
    (
    SELECT 	lig,	
    	val as colonne1,
    	null as colonne2,
    	null as colonne3  
    FROM   	tcolonne
    WHERE 	col = 'Colonne 1'
    UNION ALL
    SELECT 	lig,
    	null,
    	val,
    	null
    FROM   	tcolonne
    WHERE  	col = 'Colonne 2'
    UNION ALL
    SELECT 	lig,
    	null,
    	null,
    	val
    FROM   	tcolonne
    WHERE  	col = 'Colonne 3'
    ) xtab
    INNER JOIN tligne
    ON	tligne.lig = xtab.lig
    GROUP BY tligne.nom
    ORDER BY tligne.nom;
    --
    ---- A la mode 'MS'
    ---- Jet (et SQL-Server 2005 semble-t-il mais à confirmer quant à la syntaxe)
    --
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    TRANSFORM MAX(tcolonne.val) 
    SELECT tligne.nom
    FROM   tligne
    INNER JOIN tcolonne 
    ON tligne.lig = tcolonne.lig
    WHERE tcolonne.col IN ('Colonne 1', 'Colonne 2', 'Colonne 3') 
    GROUP BY  tligne.nom
    PIVOT  tcolonne.col
    ;
      0  0

  3. #3
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut
    Pour résumer... C'est une simple jointure

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    SELECT
       Users.Nom,
       Roles.Nom
    FROM
       Users,
       Roles,
       UsersRoles
    WHERE
       Users.IDUser = UsersRoles.IDUser AND
       Roles.IDRole = UsersRoles.IDRoles
    GROUP BY
       Users.Nom
    Mais si tu veux tous les mettre sur la même ligne, dans ce cas, je te conseille d'avoir recours à une procédure stockée. Dans ce cas, cela dépend du SGBD que tu utilises.
      0  0

  4. #4
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 10
    Points : 10
    Points
    10
    Par défaut
    Merci pour vos réponses mais ca ne correspond pas à ce que je veux.
    VOus avez mal compris le probleme et vous répondez donc à côté.
    BiMouXeTTe, ce que tu me dis serait trop facile, je sais le faire, c'est pas ca que je veux mais biensur la procédure (SQK Server) et puis de toute facon ta clause GROUP BY ne marche pas.

    En bref, dans tes solutions, TheLeadingEdge, le nombre de colonne est prédéfinie et de plus, ca n'implique que deux tables. EN ce qui me concerne, le nombre de colonnes est inconnu car un utilisateur peut avoir entre 1 et N rôles et il faut tous les afficher !

    J'espère que vous aurez mieux compris mon probleme.
    Essayez de relire le message pour mieux le comprendre.
    Merci
      0  0

  5. #5
    Membre habitué
    Homme Profil pro
    Inscrit en
    Août 2005
    Messages
    161
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Août 2005
    Messages : 161
    Points : 193
    Points
    193
    Par défaut
    Citation Envoyé par vynce
    VOus avez mal compris le probleme et vous répondez donc à côté.
    A moins que ce ne soit toi qui ne te sois pas bien fais comprendre
      0  0

  6. #6
    BiM
    BiM est déconnecté
    Expert éminent sénior
    Avatar de BiM
    Femme Profil pro
    Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT
    Inscrit en
    Janvier 2005
    Messages
    7 796
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 38
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultante/Formatrice BIRT & Ingénieur Java/J2EE/GWT

    Informations forums :
    Inscription : Janvier 2005
    Messages : 7 796
    Points : 10 765
    Points
    10 765
    Par défaut
    Oui sur SQL Server il faut mettre tous les champs affichés dans le GROUP BY.

    Bien construit toi un petit algorithme et ensuite cherche pas à pas pour construire ta proc
      0  0

  7. #7
    Membre habitué Avatar de souellet
    Profil pro
    Inscrit en
    Juillet 2003
    Messages
    155
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : Canada

    Informations forums :
    Inscription : Juillet 2003
    Messages : 155
    Points : 171
    Points
    171
    Par défaut
    Citation Envoyé par MadCat34
    Citation Envoyé par vynce
    VOus avez mal compris le probleme et vous répondez donc à côté.
    A moins que ce ne soit toi qui ne te sois pas bien fais comprendre
    Probablement qu'en ayant lu les règles du forum, la question aurait été posée autrement afin qu'on ne te réponde pas "à côté" ou qu'on te réponde tout simplement.

    Pour ceux qui ont tenté de répondre... "à côté"
      0  0

  8. #8
    Membre expert
    Avatar de TheLeadingEdge
    Inscrit en
    Mai 2005
    Messages
    1 199
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 1 199
    Points : 3 103
    Points
    3 103
    Par défaut
    Citation Envoyé par vynce
    VOus avez mal compris le probleme et vous répondez donc à côté.
    Je te remercie

    Ce que tu veux faire s'appelle 1 matrice. (Ou Crosstab ou Matrix).

    J'ai pris du temps pour faire 1 synthèse à peu près exhaustive des solutions qui ont déjà été proposées pour contourner le problème.
    Car cette demande est à peu près aussi vieille que le SQL.
    1 règle de base de SQL et des bases de données relationnelles est la '1ere Forme Normale' (pas de multivaluées), donc si l'on s'en tient à la norme, en l'état actuel on ne peut pas faire ce que tu veux en SQL.
    L'autre solution t'a été proposée par Bimouxette. Tu fais 1 procédure stockée.
      0  0

  9. #9
    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
      0  0

  10. #10
    Membre à l'essai
    Inscrit en
    Juillet 2004
    Messages
    10
    Détails du profil
    Informations forums :
    Inscription : Juillet 2004
    Messages : 10
    Points : 10
    Points
    10
    Par défaut
    Merci encore pour vos réponses.
    Bon finalement j'ai fait avec une autre solution, certes pas géniale mais au moins ca marche nickel et puis j'ai pas non plus besoin d'optimiser à fond, donc c'est pas grave. Donc en fait, pour chaque utilisateur, je refait un requete pour connaître ses rôles.

    Mais sinon, juste un truc : pour ceux qui sont vexés de pas avoir comrpis ma question, je vous trouve très susceptibles, c'est pas grave les gars, faut prendre ca cool ! Je voulais pas être méchant ou quoi que ce soit dans mon message mais juste vous informer que vos réponses ne correspondaient pas à ce que je cherchais, c'est tout ! Je vois pas ce qu'il y a de scandaleux

    Encore une fois, je maintiens que mon explication peut être difficilement meilleure, de plus je donne un exemple très simple pour illustrer. Mais peut être que certains ne savent pas ce que c'est qu'une relation N-N (je parle pour TheLeadingEdge qui me propose de respecter les formes normales mais encore une fois, relis ma question et tu verra qu'elle les respecte, et pas seulement la 1ere...). Un utilisateur peut avoir un ou plusieurs rôles (1-N) et un rôle peut être tenu par 1 ou plusieurs utilisateurs (1-N), ce qui fait du N-N, ce qui fait qu'on doit contruire une table entre les deux... un cas plus que classique en SQL...

    Probablement qu'en ayant lu les règles du forum, la question aurait été posée autrement afin qu'on ne te réponde pas "à côté" ou qu'on te réponde tout simplement.
    Encore une fois, je maintiens que ma question est tout à fait compréhensible, est-ce que tu l'a lu au moins pour juger ?
      0  0

  11. #11
    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
    Citation Envoyé par vynce
    Mais sinon, juste un truc : pour ceux qui sont vexés de pas avoir comrpis ma question, je vous trouve très susceptibles, c'est pas grave les gars, faut prendre ca cool !
    ...

    Encore une fois, je maintiens que ma question est tout à fait compréhensible, est-ce que tu l'a lu au moins pour juger ?
    No comment !
      0  0

  12. #12
    Xo
    Xo est déconnecté
    Expert confirmé
    Avatar de Xo
    Inscrit en
    Janvier 2005
    Messages
    2 701
    Détails du profil
    Informations personnelles :
    Âge : 51

    Informations forums :
    Inscription : Janvier 2005
    Messages : 2 701
    Points : 4 238
    Points
    4 238
    Par défaut
    vynce, je n'ai pas lu la partie "technique", pas le temps. Je verouille pour éviter la foire d'empoigne. Si ceux qui t'ont répondu ne t'ont pas compris, fais-le savoir de manière un peu moins abrupte, surtout pour ceux qui se sont donnés la peine de creuser un peu

    VOus avez mal compris le probleme et vous répondez donc à côté.
    Comme diraient certains, je te trouve un peu péremptoire

    Essayez de relire le message pour mieux le comprendre.
    Ou alors explique-toi mieux ?

    A bon entendeur,
      0  0

Discussion fermée
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 10
    Dernier message: 05/02/2009, 10h18
  2. Requête d'ajout de données entre 2 tables
    Par kiki.gaby dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 04/11/2008, 14h30
  3. Relation et contrainte entre deux tables
    Par maniravitch dans le forum Requêtes
    Réponses: 3
    Dernier message: 29/01/2008, 16h34
  4. [Hibernate] Faire une requête avec relation NN
    Par n@n¤u dans le forum Hibernate
    Réponses: 20
    Dernier message: 25/07/2006, 10h39
  5. Mettre une relation 1,1 entre 2 tables
    Par borgfabr dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 11/05/2005, 17h20

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