我正在为分类帐表创建一个清理视图,其中交易在源系统中以分层结构存储。我想创建一个附加列“Group_Id”来标识属于同一事务集的所有记录。
我的目标是找到填充
Group_Id
列的最有效方法,如下例所示:
条目_编号 | 已关闭_按_条目_否 | 组_Id |
---|---|---|
1 | 4 | 1 |
2 | 4 | 1 |
3 | 4 | 1 |
4 | 5 | 1 |
5 | 0 | 1 |
6 | 9 | 2 |
7 | 9 | 2 |
8 | 9 | 2 |
9 | 11 | 2 |
10 | 11 | 2 |
11 | 0 | 2 |
12 | 14 | 3 |
13 | 14 | 3 |
14 | 0 | 3 |
15 | 16 | 4 |
16 | 0 | 4 |
17 | 0 | 5 |
18 | 20 | 6 |
19 | 20 | 6 |
20 | 22 | 6 |
21 | 22 | 6 |
22 | 0 | 6 |
其中
Closed_By_Entry_No
是 Parent_Id
,Entry_No
是 Child_Id
,每组最上面的 Parent_Id
的 Child_Id
始终为 0(零)。
我面临的挑战是我的数据集中没有一个层次结构,我有数十万个层次结构。通常,每组由两条记录组成:1 张发票 + 1 笔付款(总共占记录的 70%),但还有更详细的情况,如上面的示例,我可以使用例如15 张发票 + 3 笔付款 + 1 张贷方票据。我需要以一种可以将它们视为单个主题以进行进一步计算的方式来识别所有这些集合。
我现在解决这个问题的唯一想法是只用
提供光标SELECT Entry_No, Closed_By_Entry_No
FROM table
WHERE Closed_By_Entry_No = 0
在结果集中滚动此游标,将每个候选记录发送到包含递归 CTE 的存储过程,以从原始表中读取层次结构,并从游标索引本身增量填充
Group_Id
并将结果存储在临时表中。然后从临时表继续......
必须有一种更简单的方法,既不使用游标也不使用临时表。
这是一个简单的递归公用表表达式:
declare @LedgerEntries as Table ( Entry_No Int, Closed_By_Entry_No Int, Group_Id Int );
insert into @LedgerEntries ( Entry_No, Closed_By_Entry_No, Group_Id ) values
( 1, 4, 1 ),
( 2, 4, 1 ),
( 3, 4, 1 ),
( 4, 5, 1 ),
( 5, 0, 1 ),
( 6, 9, 2 ),
( 7, 9, 2 ),
( 8, 9, 2 ),
( 9, 11, 2 ),
( 10, 11, 2 ),
( 11, 0, 2 ),
( 12, 14, 3 ),
( 13, 14, 3 ),
( 14, 0, 3 ),
( 15, 16, 4 ),
( 16, 0, 4 ),
( 17, 0, 5 ),
( 18, 20, 6 ),
( 19, 20, 6 ),
( 20, 22, 6 ),
( 21, 22, 6 ),
( 22, 0, 6 );
select * from @LedgerEntries;
with Hierarchy as (
-- Anchor query.
-- Start with the closed by zero ledger entries and assign a group id.
select Entry_No, Closed_By_Entry_No, Group_Id,
Row_Number( ) over ( order by Entry_No ) as NewGroupId
from @LedgerEntries
where Closed_By_Entry_No = 0
union all
-- Recursive query.
-- Add each level, working backwards, of ledger entries and propagate the new group id.
select LE.Entry_No, LE.Closed_By_Entry_No, LE.Group_Id, H.NewGroupId
from Hierarchy as H inner join
@LedgerEntries as LE on LE.Closed_By_Entry_No = H.Entry_No
)
select *
from Hierarchy
order by Entry_No;