SQL Server CTE以递归方式获取给定行的所有链接行

时间:2012-07-19 14:57:16

标签: tsql sql-server-2005

我有一张包含以下详细信息的表格:

-- SQL
CREATE TABLE [dbo].[LedgerTbl](
    [LedgerID] [int] NOT NULL,
    [Name] [varchar](50) NOT NULL,
    [ParentID] [int] NULL,
    [Cr Amt] [decimal](8, 2) NOT NULL,
    [Dr Amt] [decimal](8, 2) NOT NULL,
 CONSTRAINT [PK_LedgerTbl] PRIMARY KEY CLUSTERED 
(
    [LedgerID] 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
-- Data
INSERT [dbo].[LedgerTbl] ([LedgerID], [Name], [ParentID], [Cr Amt], [Dr Amt]) VALUES (17, N'L1 Ledger', 20, CAST(25252.00 AS Decimal(8, 2)), CAST(0.00 AS Decimal(8, 2)))
INSERT [dbo].[LedgerTbl] ([LedgerID], [Name], [ParentID], [Cr Amt], [Dr Amt]) VALUES (18, N'L2 Ledger', 20, CAST(9000.00 AS Decimal(8, 2)), CAST(0.00 AS Decimal(8, 2)))
INSERT [dbo].[LedgerTbl] ([LedgerID], [Name], [ParentID], [Cr Amt], [Dr Amt]) VALUES (20, N'Master Ledger', NULL, CAST(0.00 AS Decimal(8, 2)), CAST(6900.00 AS Decimal(8, 2)))
INSERT [dbo].[LedgerTbl] ([LedgerID], [Name], [ParentID], [Cr Amt], [Dr Amt]) VALUES (45, N'L1.1 Ledger', 17, CAST(361.00 AS Decimal(8, 2)), CAST(0.00 AS Decimal(8, 2)))
INSERT [dbo].[LedgerTbl] ([LedgerID], [Name], [ParentID], [Cr Amt], [Dr Amt]) VALUES (46, N'L1.1.1 Ledger', 45, CAST(6541.00 AS Decimal(8, 2)), CAST(0.00 AS Decimal(8, 2)))
INSERT [dbo].[LedgerTbl] ([LedgerID], [Name], [ParentID], [Cr Amt], [Dr Amt]) VALUES (47, N'L1.1.2 Ledger', 45, CAST(321.00 AS Decimal(8, 2)), CAST(0.00 AS Decimal(8, 2)))

GO
ALTER TABLE [dbo].[LedgerTbl]  WITH CHECK ADD  CONSTRAINT [FK_LedgerTbl_LedgerTbl] FOREIGN KEY([ParentID])
REFERENCES [dbo].[LedgerTbl] ([LedgerID])
GO
ALTER TABLE [dbo].[LedgerTbl] CHECK CONSTRAINT [FK_LedgerTbl_LedgerTbl]
GO

示例数据如下:

LedgerID    Name            ParentID     Cr Amt     Dr Amt
20          Master Ledger   NULL           0.00    6900.00
17          L1 Ledger       20         25252.00       0.00
18          L2 Ledger       20          9000.00       0.00
45          L1.1 Ledger     17           361.00       0.00
46          L1.1.1 Ledger   45          6541.00       0.00
47          L1.1.2 Ledger   45           321.00       0.00 

在上面的LedgerID 20表中,我需要所有链接的分类账(在所有级别),这些分类账直接或间接地链接到这个分类账。在上表中,所有分类账直接与20相关联 如果我查询分类帐20的余额,它应该显示如下(添加所有级别的所有链接分类帐的所有Cr Amt和Dr Amount):

Cr Bal        Dr Bal
41475.00    6900.00

由于所有分类账直接或间接地与20联系,因此所有Cr Amt和Dr Amt都被总结。
在添加所有链接/未链接的LedgerID的Cr Amt和Dr Amt之后,结果应该是这样的:

LedgerID   Tot. Cr Amt  Tot Dr Amt
20         41475.00    6900.00
18          9000.00       0.00
17         32475.00       0.00
45          7223.00       0.00
46          6541.00       0.00
47           321.00       0.00

请注意,分类帐18没有任何子分类帐,因此无需添加任何余额。

请使用CTE或任何其他方法帮助实现此目的。提前谢谢。

这是我尝试过的:

;WITH RecursiveLedger(LedgerID, [Name],[Cr Amt], [Dr Amt], LevelNum, LevelIndex, ParentID)
AS (
       SELECT lg.LedgerID,
              lg.[Name],
              lg.[Cr Amt],
              lg.[Dr Amt],
              1 AS LevelNum,
              CAST(lg.LedgerID AS VARCHAR) AS LevelIndex,
              lg.ParentID 
       FROM   [LedgerTbl] lg
       WHERE  lg.ParentID IS NULL
       UNION ALL
       SELECT l.LedgerID,
              l.[Name],
              l.[Cr Amt],
              l.[Dr Amt],
              r.LevelNum + 1 AS LevelNum,
              CAST(r.LevelIndex + '.' + CAST(ROW_NUMBER() OVER(ORDER BY l.ParentID) AS VARCHAR) AS VARCHAR) AS LevelIndex,
              l.ParentID 
       FROM   [LedgerTbl] l,
              RecursiveLedger r
       WHERE  r.LedgerID = l.ParentID
   ) SELECT * FROM   RecursiveLedger

1 个答案:

答案 0 :(得分:1)

with anc as 
(
    select ledgerid, parentid
    from [LedgerTbl] where parentid is not null
    union all
    select c.ledgerid, isnull(anc.parentid, anc.parentid)
    from anc 
        inner join [LedgerTbl] c on anc.ledgerid = c.parentid
), anc2 as
(
    select * from anc
    union all
    select ledgerid, ledgerid
    from ledgertbl 
)
select  a.parentid,
        sum(l.[Cr Amt]), 
        sum(l.[dr Amt]) 
from anc2 a
    inner join ledgertbl l on a.ledgerid = l.ledgerid
group by a.parentid
order by a.parentid;