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 :

Regrouper des lignes avec un INNER JOIN


Sujet :

Langage SQL

  1. #1
    Expert confirmé Avatar de Barsy
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    1 484
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 484
    Points : 5 277
    Points
    5 277
    Par défaut Regrouper des lignes avec un INNER JOIN
    Bonjour,

    J'ai une requête qui doit me retourner un résultat que j'affiche ensuite directement dans un DataGrid. Dans cette requête, j'utilise des tables qui on des jointures n-n.

    Ca donne à peu près ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    SELECT table1.val1, table3.val2
    FROM
    table1
    INNER JOIN table2 ON table1.t1ID = table2.t1ID
    INNER JOIN table3 ON table2.t3ID = table3.t3ID
    Bien entendu, à chaque ligne de "table1" correspondent plusieurs ligne de "table3".

    Ce que j'aimerais, ce serait pouvoir regrouper toutes ces lignes en une seule en faisant une colonne unique dans laquelle les valeurs de table3 seraient séparées par un caractère (par exemple une virgule).

    Je vois comment arriver à ce résultant en "développant" mais cela ralentirait considérablement l'exécution de ma requête. Est-ce que quelqu'un n'aurait pas un moyen simple à proposer ?

    Merci
    "tatatatatatatatataaa !! tata taaa !! tata taaa !! tatatata tataaa !! tata taaa !! tata taaa !!"

  2. #2
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Vous pouvez le faire en post traitement dans votre application.
    Certains SGBD proposent des solutions de contournement si besoin, quel est le votre ?

  3. #3
    Expert confirmé Avatar de Barsy
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    1 484
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 484
    Points : 5 277
    Points
    5 277
    Par défaut
    Citation Envoyé par Waldar Voir le message
    Vous pouvez le faire en post traitement dans votre application.
    Certains SGBD proposent des solutions de contournement si besoin, quel est le votre ?
    J'aimerai éviter de le faire en "post traitement". ça ralentit aussi le traitement. Mon SGBD est MS SQL Server.

    Je suis en train d'essayer de passer par une fonction. Je vais voir ce que ça donne.
    "tatatatatatatatataaa !! tata taaa !! tata taaa !! tatatata tataaa !! tata taaa !! tata taaa !!"

  4. #4
    Modérateur

    Avatar de CinePhil
    Homme Profil pro
    Ingénieur d'études en informatique
    Inscrit en
    Août 2006
    Messages
    16 799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur d'études en informatique
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2006
    Messages : 16 799
    Points : 34 031
    Points
    34 031
    Billets dans le blog
    14
    Par défaut
    Ce que vous cherchez à faire est de la cosmétique et n'est pas le boulot de SQL. Ce sera probablement plus rapide dans le programme applicatif.
    Philippe Leménager. Ingénieur d'étude à l'École Nationale Supérieure de Formation de l'Enseignement Agricole. Autoentrepreneur.
    Mon ancien blog sur la conception des BDD, le langage SQL, le PHP... et mon nouveau blog sur les mêmes sujets.
    « Ce que l'on conçoit bien s'énonce clairement, et les mots pour le dire arrivent aisément ». (Nicolas Boileau)
    À la maison comme au bureau, j'utilise la suite Linux Mageïa !

  5. #5
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    fsmrel a rédigé plusieurs solutions pour MS SQL Server ici :
    http://www.developpez.net/forums/d78...n/#post4552843

  6. #6
    Expert confirmé Avatar de Barsy
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    1 484
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 484
    Points : 5 277
    Points
    5 277
    Par défaut
    Je reconnais que c'est de la cosmétique. Mais, bien que ce ne soit pas au SGDB de faire le boulot, il n'y a pas de mal à vouloir récupérer les données sous la forme la plus proche du résultat voulu quand c'est possible.

    Concernant l'utilisation de CURSOR, c'est ce dont je voulais parler dans mon premier message quand je disais "en développant" mais ces derniers plombent réellement les performances. C'est pourquoi je suis venu ici voir s'il n'y avait pas un autre moyen auquel je n'aurais pas pensé et qui permettrais de faire le traitement sur l'ensemble d'un SELECT d'un seul coup.

    Merci cependant pour vos réponses,

    Barsy
    "tatatatatatatatataaa !! tata taaa !! tata taaa !! tatatata tataaa !! tata taaa !! tata taaa !!"

  7. #7
    Modérateur
    Avatar de Waldar
    Homme Profil pro
    Customer Success Manager @Vertica
    Inscrit en
    Septembre 2008
    Messages
    8 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Customer Success Manager @Vertica
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2008
    Messages : 8 452
    Points : 17 820
    Points
    17 820
    Par défaut
    Si vous êtes sur la version 2005 ou plus, vous pouvez construire la liste avec une CTE recursive.

    Il y a peut-être un tutorial chez SQLPro ou Elsuket, mais je n'en suis pas certain.

    N'hésitez pas à rechercher sur internet avec les mots "string aggregation".

  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
    Bonjour,

    Ce que j'aimerais, ce serait pouvoir regrouper toutes ces lignes en une seule en faisant une colonne unique dans laquelle les valeurs de table3 seraient séparées par un caractère (par exemple une virgule).
    Si tu veux une seule colonne multivaluée en sortie tu peux le faire avec une requête récursive.
    Comme ce n'est pas vraiment un graphe en entrée, j'ai rajouté une étape numérotation pour simplifier la jointure. Elle ne te sera peut-être pas nécessaire.
    Coté perf vs une procédure stockée, je ne sais pas quel est le mieux. Eventuellement fait nous un retour là dessus.

    1 val1
    1 val2
    1 val3
    2 val1
    2 val2
    2 val3
    2 val4
    2 val6
    2 val9
    3 val3
    WITH R (id, rk, val)
    AS
    (
    SELECT id,
    1,
    CAST (MIN(val) AS VARCHAR(255))
    FROM T H
    GROUP BY id
    UNION ALL
    SELECT D.id,
    D.rk,
    H.val CONCAT ',' CONCAT D.val
    FROM R H,
    (
    SELECT id,
    DENSE_RANK () OVER (PARTITION BY id ORDER BY val) AS rk,
    val
    FROM T
    ) AS D
    WHERE D.id = H.id
    AND D.rk = H.rk + 1
    )
    SELECT id,
    MAX(val)
    FROM R
    GROUP BY id;
    1 val1,val2,val3
    2 val1,val2,val3,val4,val6,val9
    3 val3

    3 enregistrement(s) sélectionné(s)

  9. #9
    Expert confirmé Avatar de Barsy
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    1 484
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 484
    Points : 5 277
    Points
    5 277
    Par défaut
    Merci pour vos réponses.

    @TheLeadingEdge : Quand j'essaie ta requete, il me retourne les erreurs suivantes :

    La colonne 'D.id' n'est pas valide dans la liste de sélection parce qu'elle n'est pas contenue dans une fonction d'agrégation ou dans la clause GROUP BY.
    et si je mets un GROUP BY, il me dit

    Les fonctions GROUP BY, HAVING ou d'agrégation ne sont pas autorisées dans la partie récursive d'une expression de table commune récursive 'ListStatus'.
    Voici ma requête après l'avoir adaptée :

    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
     
    DECLARE @tempTable TABLE 
    (
    	t1ID INT,
    	t3ID INT
    )
     
    INSERT INTO @tempTable 
    	SELECT 
    		table1.t1ID, 
    		table2.t3ID 
    	FROM
    		table1
    		INNER JOIN table2 ON table1.t1ID = table2.t1ID;
     
    WITH R (id, rk, val) AS
    (
    	SELECT 
    		t1ID,
    		1,
    		CAST (MIN(t3ID) AS VARCHAR(255))
    	FROM @tempTable H
    	GROUP BY t1ID
    	UNION ALL
    	SELECT
    		D.id,
    		D.rk,
    		CAST (MIN(H.val) AS VARCHAR(255)) + ',' + CAST (MIN(D.val) AS VARCHAR(255))
    	FROM
    		R H,
    		(
    			SELECT        
    				t1ID AS id,
    				DENSE_RANK() OVER (PARTITION BY t1ID ORDER BY t3ID) AS RK,
    				t3ID AS VAL
    			FROM @tempTable 
    		) AS D
    	WHERE     
    		D.id = H.id
    	AND
    		D.rk = H.rk + 1
    )
    SELECT
    	id,
        MAX(val)
    FROM R
    GROUP BY id
    "tatatatatatatatataaa !! tata taaa !! tata taaa !! tatatata tataaa !! tata taaa !! tata taaa !!"

  10. #10
    Expert confirmé Avatar de Barsy
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    1 484
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 484
    Points : 5 277
    Points
    5 277
    Par défaut
    J'ai trouvé mon erreur, ça vient de deux "MIN" que j'ai mis en trop.

    J'ai encore un problème de type. Je vais finir de résoudre ça et ça devrait être bon.
    "tatatatatatatatataaa !! tata taaa !! tata taaa !! tatatata tataaa !! tata taaa !! tata taaa !!"

  11. #11
    Expert confirmé Avatar de Barsy
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    1 484
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 484
    Points : 5 277
    Points
    5 277
    Par défaut
    C'est bon, ça fonctionne : il faut mettre un CAST(... AS VARCHAR(255)) autour du 1 et autour du DENSE_RANK() (...).

    Par contre, la performance est très mauvaise. La requête met environ 3 secondes sur une table de 1000 lignes.

    Bref, tant pis, je vais me débrouiller autrement, merci quand même pour vos réponses.

    Barsy

    PS : je mets le tag résolu.
    "tatatatatatatatataaa !! tata taaa !! tata taaa !! tatatata tataaa !! tata taaa !! tata taaa !!"

  12. #12
    Expert confirmé Avatar de Barsy
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2007
    Messages
    1 484
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2007
    Messages : 1 484
    Points : 5 277
    Points
    5 277
    Par défaut
    Bon, désolé, c'est mon quatrième post à la suite. Mais j'ai trouvé !!

    Merci à Laurent Banon

    La réponse en quelques ligne :

    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
    SELECT
    	t1ID,
        t3IDs  = LEFT(o.list, LEN(o.list)-1)
     
    FROM
    	table1 t1
    CROSS APPLY
    (
        SELECT
            CONVERT(VARCHAR(12), t3ID) + ',' AS [text()]
        FROM
            table2 t2
        WHERE
            t2.t1ID = t1.t1ID
        ORDER BY
            t3ID
        FOR XML PATH('')
    ) o (list)
    ORDER BY
        t1ID
    Le temps d'exécution de la requête est quasi immédiat. Ca marche nickel !!

    Voilà, maintenant, c'est résolu pour de bon.
    "tatatatatatatatataaa !! tata taaa !! tata taaa !! tatatata tataaa !! tata taaa !! tata taaa !!"

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

Discussions similaires

  1. [Jlist] faire des lignes avec boutons
    Par matt22 dans le forum Composants
    Réponses: 1
    Dernier message: 27/11/2006, 16h21
  2. Comment changer les couleurs des lignes avec displaytag
    Par rlnd23 dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 09/10/2006, 13h52
  3. une requête avec plusieurs INNER JOIN, cmt faire ?
    Par elhosni dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 10/01/2006, 17h55
  4. [Requete] Comment ignorer des lignes avec un LOAD DATA
    Par frangin2003 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 09/11/2005, 12h14
  5. requête sql avec clause INNER JOIN
    Par new_wave dans le forum Langage SQL
    Réponses: 1
    Dernier message: 12/08/2005, 15h47

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