2010-02-26 4 views
18

para una estructura de datos simple, como así:Cuenta del número de niños en los datos de SQL jerárquicos

ID parentID Text  Price 
1     Root 
2  1   Flowers 
3  1   Electro 
4  2   Rose  10 
5  2   Violet  5 
6  4   Red Rose 12 
7  3   Television 100 
8  3   Radio  70 
9  8   Webradio 90 

Como referencia, el árbol de jerarquía se ve así:

ID Text  Price 
1  Root 
|2 Flowers 
|-4 Rose  10 
| |-6 Red Rose 12 
|-5 Violet  5 
|3 Electro 
|-7 Television 100 
|-8 Radio  70 
    |-9 Webradio 90 

me gustaría contar la cantidad de niños por nivel Así que me gustaría conseguir una nueva columna "NoOfChildren", así:

ID parentID Text  Price NoOfChildren 
1     Root    8 
2  1   Flowers   3 
3  1   Electro   3 
4  2   Rose  10  1 
5  2   Violet  5  0 
6  4   Red Rose 12  0 
7  3   Television 100 0 
8  3   Radio  70  1 
9  8   Webradio 90  0 

He leído algunas cosas sobre los datos jerárquicos, pero de alguna manera se queda atascado en el múltiplo se une interior sobre los parentIDs. Quizás alguien podría ayudarme aquí.

+0

Usted HIERARCHIE árbol no coincide con sus entradas. –

+0

Y su resultado no parece coincidir con su jerarquía . Al mirar su jerarquía, supongo que ID's 4 y 7 tienen 0 hijos. –

+0

está en lo correcto, arruinado con el árbol de jerarquía + la salida, arreglará –

Respuesta

21

El uso de un CTE le daría lo que desea.

  • Revise recursivamente a todos los niños, recordando la raíz.
  • COUNT elementos para cada raíz.
  • JOIN estos nuevamente con su tabla original para producir los resultados.

de datos de prueba

DECLARE @Data TABLE (
    ID INTEGER PRIMARY KEY 
    , ParentID INTEGER 
    , Text VARCHAR(32) 
    , Price INTEGER 
) 

INSERT INTO @Data 
    SELECT 1, Null, 'Root', NULL 
    UNION ALL SELECT 2, 1, 'Flowers', NULL 
    UNION ALL SELECT 3, 1, 'Electro', NULL 
    UNION ALL SELECT 4, 2, 'Rose', 10 
    UNION ALL SELECT 5, 2, 'Violet', 5 
    UNION ALL SELECT 6, 4, 'Red Rose', 12 
    UNION ALL SELECT 7, 3, 'Television', 100 
    UNION ALL SELECT 8, 3, 'Radio', 70 
    UNION ALL SELECT 9, 8, 'Webradio', 90 

instrucción SQL

;WITH ChildrenCTE AS (
    SELECT RootID = ID, ID 
    FROM @Data 
    UNION ALL 
    SELECT cte.RootID, d.ID 
    FROM ChildrenCTE cte 
      INNER JOIN @Data d ON d.ParentID = cte.ID 
) 
SELECT d.ID, d.ParentID, d.Text, d.Price, cnt.Children 
FROM @Data d 
     INNER JOIN (
      SELECT ID = RootID, Children = COUNT(*) - 1 
      FROM ChildrenCTE 
      GROUP BY RootID 
     ) cnt ON cnt.ID = d.ID 
+0

Gracias por su respuesta explícita, solución perfecta. ¿Quieres aclararme sobre el uso de ";"? A veces obtengo un error de sintaxis cuando uso declaraciones WITH, que no tengo esa desagradable ";" ¿Siempre tengo que "escapar" CON las declaraciones con un apéndice? –

+3

@moontear: la cláusula 'WITH' que define un' CTE' puede mezclarse con la cláusula 'WITH' que define una sugerencia de tabla. El primero debe separarse explícitamente con un punto y coma si no es la primera declaración en el lote. – Quassnoi

+0

+1, casi tan difícil como una APLICACIÓN CRUZADA utilizando una función dividida, aunque no es tan común ;-) –

5

considerar el uso de un árbol preorden camino recorrido modificado de almacenar los datos jerárquicos. Ver http://www.sitepoint.com/hierarchical-data-database/

Determinar número de niños para cualquier nodo se convierte entonces en un simple:

SELECT (right-left-1)/2 AS num_children FROM ... 
+0

Me ahorraste mucho tiempo. La mejor respuesta para mí :) –

Cuestiones relacionadas