CTE Hierachy по убыванию, но поднимая дочерние узлы, а не родителей от предка - PullRequest
2 голосов
/ 23 марта 2011

Объяснение

ОК, заголовок может быть немного большим:)

Я вставлю сценарии в конце.

Представьте себе следующее n-арное дерево

.  
|  
---1 **(25)**   
   |  
    -----1.1 **(13)**  
    |    |  
    |    ----1.1.1 (1)  
    |    |  
    |    ----1.1.2 **(7)**  
    |    |    |
    |    |    ----1.1.2.1 (4)        
    |    |    |
    |    |    ----1.1.2.2 (3)  
    |    |    
    |    ----1.1.3 (5)  
    |    
    -----1.2 (2)  
    | 
    |    
    -----1.3 (10)  

И так далее, где корневая ветка "."также может иметь ветвь 2,3, n, и эта ветвь также будет иметь свою собственную произвольную древовидную форму с n-ветвями, возможными из любого данного узла.Значения в скобках в конце каждого узла являются, так сказать, значениями в узле.Думайте о них как о счетах с субсчетами, в которых родительский учет представляет собой сумму дочерних учетных записей.

То, что я пытаюсь сделать с CTE, - это получить все [вспомогательные] учетные записи непосредственно под родительским,Таким образом, для предоставления 1.1 в качестве точки поиска, он будет извлекать всю эту ветвь дерева.Но, если я попытаюсь быть умным и суммировать возвращаемые значения, я *1014* буду добавлять (для этого конкретного примера) 1.1.2 дважды, один раз через суммирование его субсчетов,второе суммированием значения, которое оно само содержит.

Как бы я поступил примерно так?

Спасибо zillion :)

Вот сценарии:

Сценарии

Таблица

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[Account](
    [ID] [nvarchar](50) NOT NULL,
    [ParentID] [nvarchar](50) NULL,
    [Value] [float] NOT NULL,
    [HasChild] [bit] NOT NULL,
 CONSTRAINT [PK_Account] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF,     ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

ALTER TABLE [dbo].[Account]  WITH CHECK ADD  CONSTRAINT [FK_Account_Account] FOREIGN     KEY([ParentID])
REFERENCES [dbo].[Account] ([ID])
GO

ALTER TABLE [dbo].[Account] CHECK CONSTRAINT [FK_Account_Account]
GO

ALTER TABLE [dbo].[Account] ADD  CONSTRAINT [DF_Account_HasChild]  DEFAULT ((0)) FOR     [HasChild]
GO

Сценарий CTE

WITH 
DescendToChild([ID],ParentID,Value)
AS
(

    --base case
    SELECT [ID],ParentID,Value FROM Account
    Where ParentID = '1.1'


    UNION ALL

    ----recursive step
    SELECT
        A.[ID],A.ParentID,A.Value FROM Account as A
        INNER JOIN DescendToChild D on A.ParentID = D.ID
)
select * from DescendToChild;

Ответы [ 2 ]

3 голосов
/ 23 марта 2011

Вот решение, основанное на ваших данных образца.Он работает только суммированием тех узлов без дочерних элементов:

DECLARE @tree TABLE
(id INT
,parentid INT
,nodeName VARCHAR(10)
,VALUE INT
)

INSERT @tree (id,parentid,nodeName,VALUE)
VALUES
(1,NULL,'.',NULL),
(2,1,'1',25),
(3,2,'1.1',13),
(4,2,'1.2',2),
(5,2,'1.3',10),
(6,3,'1.1.1',1),
(7,3,'1.1.2',7),
(8,3,'1.1.3',5),
(9,7,'1.1.2.1',4),
(10,7,'1.1.2.2',3)


;WITH recCTE
AS
(
     SELECT id, parentid, nodeName, value, 
            CASE WHEN EXISTS (SELECT 1 FROM @tree AS t1 WHERE t1.parentid = t.id) THEN 1 ELSE 0 END AS hasChildren
     FROM @tree AS t
     WHERE nodeName = '1.1'

     UNION ALL

     SELECT t.id, t.parentid, t.nodeName, t.value, 
            CASE WHEN EXISTS (SELECT 1 FROM @tree AS t1 WHERE t1.parentid = t.id) THEN 1 ELSE 0 END AS hasChildren
     FROM @tree AS t
     JOIN recCTE AS r
     ON   r.id = t.parentid

)
SELECT SUM(VALUE)
FROM recCTE 
WHERE hasChildren = 0
OPTION (MAXRECURSION 0)
0 голосов
...