2016-06-06 1 views
0

Trouvé un problème intéressant ici.Trier par (parent, groupe d'enfants) et les valeurs par ordre alphabétique

ResultID ParentID ValueX 
-------------------------- 
1   0  GrandParent 
2   1  Parent1 
3   1  Parent2 
4   2  Child1 
5   2  Child2 
6   3  Child3 
7   3  Child4 

Je veux que mon résultat de la requête pour ressembler à ceci:

ResultID ParentID ValueX 
-------------------------- 
1   0  GrandParent 
2   1  Parent1 
4   2  Child1 
5   2  Child2 
3   1  Parent2 
6   3  Child3 
7   3  Child4 

Si le ParentID est 0, cela signifie que c'est une catégorie importante. Si ParentID est supérieur à 0, cela signifie que c'est une catégorie mineure, un enfant du parent.

Alors que les parents ont besoin d'être commandés A-Z et les enfants ont besoin d'être commandés A-Z en tant que groupe et dans ce groupe, les valeurs doivent être pris en considération pour le tri par ordre alphabétique. Ce ne se limite pas à 3 niveaux et peut aller jusqu'à 10.

Pouvez-vous me aider à obtenir ce commandé correctement?

WITH resultset (resultid, parentid, valuex) AS (
SELECT 1,0,'Grandparent' FROM dual UNION ALL 
SELECT 2,1,'Parent1' FROM dual UNION ALL 
SELECT 3,1,'Parent2' FROM dual UNION ALL 
SELECT 4,2,'Child1' FROM dual UNION ALL 
SELECT 5,2,'Child2' FROM dual UNION ALL 
SELECT 6,3,'Child3' FROM dual UNION ALL 
SELECT 7,3,'Child4' FROM dual) 
SELECT ResultID , ParentID, ValueX 
FROM resultset 
ORDER BY ???? 

Répondre

1

Vous pouvez le faire par auto-adhésion pour générer une liste de valeurs de la hiérarchie à l'ordre sur, comme indiqué dans le code ci-dessous. J'ai développé pour ajouter un niveau de hiérarchie supplémentaire à l'exemple original pour montrer comment cela fonctionnerait. Clairement cela dépend de connaître le nombre de niveaux de hiérarchie pour générer un plan raisonnable (vous pouvez toujours faire 10 niveaux, par exemple, mais ce sera un gros coup de performance si vous n'avez que 3 niveaux de hiérarchie dans votre exemple). En outre, j'imagine que vous pourriez utiliser une instruction EXEC pour générer le SQL nécessaire pour un niveau de hiérarchie particulier, plutôt que de générer manuellement comme ci-dessous (qui aura des optimisations comme par exemple si une entrée n'a rien à L3 il n'aura rien à L4 non plus).

WITH resultset (resultid, parentid, valuex) AS (
SELECT 1,0,'Grandparent' UNION ALL 
SELECT 2,1,'Parent1' UNION ALL 
SELECT 3,1,'Parent2' UNION ALL 
SELECT 4,2,'Child1' UNION ALL 
SELECT 5,2,'Child2' UNION ALL 
SELECT 6,3,'Child3' UNION ALL 
SELECT 7,3,'Child4' UNION ALL 
SELECT 8,4,'Child1_Child1' UNION ALL 
SELECT 9,7,'Child4_Child1' UNION ALL 
SELECT 10,6,'Child3_Child1') 
SELECT l1.resultid , l1.parentid, l1.valuex, l2.resultid l2val, l3.resultid l3val,l4.resultid l4val, 

-- rewrite COALESCE so clearer how this matches the pattern below 
CASE WHEN l4.resultid IS NULL THEN 
CASE WHEN l3.resultid IS NULL THEN 
CASE WHEN l2.resultid IS NULL THEN l1.valuex 
ELSE l2.valuex END 
ELSE l3.valuex END 
ELSE l4.valuex END o1, 

CASE WHEN l4.resultid IS NULL THEN 
CASE WHEN l3.resultid IS NULL THEN 
CASE WHEN l2.resultid IS NULL THEN '' 
ELSE l1.valuex END 
ELSE COALESCE (l2.valuex, l1.valuex, '') END 
ELSE COALESCE (l3.valuex, l2.valuex, l1.valuex, '') END o2, 

CASE WHEN l3.resultid IS NULL THEN '' 
WHEN l4.valuex IS NULL THEN l1.valuex 
ELSE l2.valuex END o3, 

CASE WHEN l2.valuex IS NULL THEN '' 
WHEN l4.valuex IS NULL THEN '' ELSE l1.valuex END o4 

FROM resultset l1 
left join resultset l2 on l1.parentid = l2.resultid 
left join resultset l3 on l2.parentid = l3.resultid 
left join resultset l4 on l3.parentid = l4.resultid 
ORDER BY o1, o2, o3, o4 

résultats (excuses pour la mauvaise mise en forme):

RESULTID PARENTID VALUEX   L2VAL L3VAL L4VAL O1   O2  O3  O4 
    1  0   Grandparent  (null) (null) (null) Grandparent   
    2  1   Parent1   1  (null) (null) Grandparent Parent1  
    4  2   Child1   2  1  (null) Grandparent Parent1 Child1 
    8  4   Child1_Child1 4  2  1  Grandparent Parent1 Child1 Child1_Child1 
    5  2   Child2   2  1  (null) Grandparent Parent1 Child2 
    3  1   Parent2   1  (null) (null) Grandparent Parent2  
    6  3   Child3   3  1  (null) Grandparent Parent2 Child3 
    10  6   Child3_Child1 6  3  1  Grandparent Parent2 Child3 Child3_Child1 
    7  3   Child4   3  1  (null) Grandparent Parent2 Child4 
    9  7   Child4_Child1 7  3  1  Grandparent Parent2 Child4 Child4_Child1 
+0

joli hack. Mais cela ne fonctionne que pour 4 niveaux. J'ai besoin de quelque chose de générique pour n'importe quel nombre de niveaux – SriniV

+0

La question initiale dit que cela peut aller jusqu'à 10 niveaux, donc vous pouvez coder en dur cela avec une auto-jointure à 10 voies. A défaut, il serait plus élégant de faire cela en utilisant EXEC pour générer la requête que vous voulez (et la limiter au nombre de niveaux de hiérarchie requis à chaque fois, comme mentionné ci-dessus, pour des raisons de performances) – mc110

1

Vous pouvez créer une liste de chemin à l'aide d'une cte récursive, ce qui suit est la syntaxe SQL Server, mais Oracle devrait être similaire:

;with cte AS (SELECT ResultID,ParentID,ValueX, List = CAST(ResultID AS VARCHAR(MAX)) 
       FROM #Table1 
       WHERE ParentID = 0 
       UNION ALL 
       SELECT a.ResultID,a.ParentID,a.ValueX, List = b.List + ','+CAST(a.ResultID AS VARCHAR(MAX)) 
       FROM #Table1 a 
       JOIN cte b 
       ON a.ParentID = b.ResultID 
       ) 
SELECT * 
FROM cte 
ORDER BY List 

Sortie:

ResultID ParentID ValueX  List 
1   0   GrandParent 1 
2   1   Parent1  1,2 
4   2   Child1  1,2,4 
5   2   Child2  1,2,5 
3   1   Parent2  1,3 
6   3   Child3  1,3,6 
7   3   Child4  1,3,7 

Vous pouvez bien bien sûr, excluez List de la liste SELECT et commandez-en toujours.

+0

malheureusement wx2 font défaut CTE – SriniV

+0

@realspirituals récursives Ah pensé qu'il était oracle. Bien sans récursion, je ne pense pas qu'il y ait une façon intelligente de faire ça. du côté db qui ne serait pas ardu, Self-joins 10x. Sans un de ceux-ci, tout ce que vous savez d'une rangée est insuffisant pour obtenir l'ordre que vous voulez. J'espère que quelqu'un d'autre a une idée géniale! –