SQL 查询以获取组和子组层次结构

SQL query to get Groups and sub groups hierarchy

帐号table

ac_id       ac_name        st_id
----------- -------------  -----------
1           LIABILITES     1
2           ASSET          1
3           REVENUE        1
4           EXPENSES       1
5           EQUITY         1

群组table

grp_id      grp_name            ac_no      grp_of     st_id   type_     cmp_id
----------- ------------------- ---------- -------- --------- --------- --------
1           Capital Account     1          0        1         0         0
2           Current Liability   1          0        1         0         0
3           Loan Liability      1          0        1         0         0
4           Suspense A/C        1          0        1         0         0
5           Current Assets      2          0        1         0         0
6           Fixed Assests       2          0        1         0         0
7           Investment          2          0        1         0         0
8           Misc. Expenses      2          0        1         0         0
9           Direct Income       3          0        1         0         0
10          Indirect Income     3          0        1         0         0
11          Sale Account        3          0        1         0         0
12          Direct Expense      4          0        1         0         0
13          Indirect Expense    4          0        1         0         0
14          Purchase Account    4          0        1         0         0
15          Sundry Creditors    2          1        1         0         0
16          Sundry Debitors     5          1        1         0         0
17          Bank Account        5          1        1         0         0
18          Cash In Hand        5          1        1         0         0
19          Duties & Taxes      2          1        1         0         0
20          Salary              12         1        1         0         0
21          Personal            5          1        1         0         0
22          Loan                2          0        1         0         0
23          Customer            16         1        1         0         0
34          Vendor              15         1        1         0         0
38          Sale Softwares      11         1        1         1         1
46          Stock In Hand       5          1        1         1         1
47          test                1          1        1         1         1
48          test in             47         1        1         1         1

查询以获取所有组层次结构。

declare @ac_no as int =2

;With CTE(grp_id,grp_name,ac_no,Level)
AS
(   SELECT 
        grp_id,grp_name,ac_no,CAST(1 AS int)
    FROM 
        Groups
    WHERE 
        grp_id in (select grp_id from Groups where (ac_no=@ac_no) and grp_of=0)
    UNION ALL
    SELECT 
        o.grp_id,o.grp_name,o.ac_no,c.Level+1
    FROM 
        Groups o
    INNER JOIN 
        CTE c 
        ON c.grp_id=o.ac_no --where o.ac_no=2 and o.grp_of=1
 )
select * from CTE

ac_no=2/3/4

的结果还可以
grp_id      grp_name            ac_no       Level
----------- ------------------- ----------- ------
5           Current Assets      2           1
6           Fixed Assests       2           1
7           Investment          2           1
8           Misc. Expenses      2           1
22          Loan                2           1
16          Sundry Debitors     5           2
17          Bank Account        5           2
18          Cash In Hand        5           2
21          Personal            5           2
46          Stock In Hand       5           2
23          Customer            16          3

但是当我尝试获取 ac_no=1 的结果时; 我收到错误:

Msg 530, Level 16, State 1, Line 4 The statement terminated. The maximum recursion 100 has been exhausted before statement completion.

我认为问题是你最终陷入无限递归,因为你有一行是它自己的 parent/child(例如 grp_id = ac_no)。

我认为如果像这样向递归成员添加限制子句应该可以工作:

DECLARE @ac_no AS int = 1;

WITH CTE (grp_id , grp_name , ac_no , Level ) AS ( 

    SELECT grp_id, grp_name, ac_no, CAST( 1 AS int )
    FROM Groups
    WHERE grp_id IN (SELECT grp_id FROM Groups WHERE ac_no = @ac_no AND grp_of = 0)

    UNION ALL

    SELECT o.grp_id, o.grp_name, o.ac_no, c.Level + 1
    FROM Groups o 
    INNER JOIN CTE c ON c.grp_id = o.ac_no --where o.ac_no=2 and o.grp_of=1
    WHERE c.ac_no <> c.grp_id 
    )

SELECT * FROM CTE;