Sql 我怎样才能编写一个程序,从I到j或类似这样的树获取级别?
我有一张像这样的桌子Sql 我怎样才能编写一个程序,从I到j或类似这样的树获取级别?,sql,sql-server,algorithm,tsql,database-design,Sql,Sql Server,Algorithm,Tsql,Database Design,我有一张像这样的桌子 Users ------------------------- id | ancestor_id | .... ------------------------- 1 | NULL | .... 2 | 1 | .... 3 | 1 | .... 4 | 3 | .... 5 | 3 | .... 那将代表一棵像树一样的树 level 1
Users
-------------------------
id | ancestor_id | ....
-------------------------
1 | NULL | ....
2 | 1 | ....
3 | 1 | ....
4 | 3 | ....
5 | 3 | ....
那将代表一棵像树一样的树
level 1 1
/ \
level 2 2 3
/ \
level 3 4 5
我想创建一个过程,返回给定用户的第I代到第j代后代:
CREATE PROCEDURE DescendantsLevel
@user_id INT,
@i INT,
@j INT
AS
....
但是,如果@j为NULL,它将返回从@i代开始的所有子代
示例:
会回来吗
-------------------------
id | ancestor_id | ....
-------------------------
1 | NULL | ....
2 | 1 | ....
3 | 1 | ....
4 | 3 | ....
5 | 3 | ....
及
会回来吗
Users
-------------------------
id | ancestor_id | ....
-------------------------
1 | NULL | ....
2 | 1 | ....
3 | 1 | ....
我有几个问题:
在SQL中,有比NULL更好的值来表示无穷大的概念吗?
我如何实现我描述的过程?
是否有更好的数据库设计方法来简化过程?
使用递归CTE:
DECLARE @test TABLE (id INT NOT NULL, ancestor_id INT NULL)
DECLARE
@id INT = 1,
@i INT = 1,
@j INT = 2
INSERT INTO @test (id, ancestor_id)
VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 3),
(5, 3)
;WITH CTE_Tree AS
(
SELECT
id,
ancestor_id,
1 AS lvl,
id AS base
FROM
@test
WHERE
id = @id
UNION ALL
SELECT
C.id,
C.ancestor_id,
P.lvl + 1 AS lvl,
P.base AS base
FROM
CTE_Tree P
INNER JOIN @test C ON C.ancestor_id = P.id
WHERE
lvl <= COALESCE(@j, 9999)
)
SELECT
id,
ancestor_id
FROM
CTE_Tree
WHERE
lvl BETWEEN @i AND COALESCE(@j, 9999)
这依赖于不超过9999个递归级别—实际上SQL Server的递归默认限制为100,因此超过100个级别时,您将得到一个错误。Lookup recursive ctes。如果您使用此设计,这将是解决此问题的最简单方法。您还可以将嵌套集模型视为邻接列表的更好替代方案。如果在第一个示例中@i为2,那么为什么返回id 1?为什么不添加级别列?使查询变得非常简单。添加级别列会将手动计算的列添加到表中-这会增加复杂性,然后可能会失去同步并导致其他问题。
Users
-------------------------
id | ancestor_id | ....
-------------------------
1 | NULL | ....
2 | 1 | ....
3 | 1 | ....
DECLARE @test TABLE (id INT NOT NULL, ancestor_id INT NULL)
DECLARE
@id INT = 1,
@i INT = 1,
@j INT = 2
INSERT INTO @test (id, ancestor_id)
VALUES
(1, NULL),
(2, 1),
(3, 1),
(4, 3),
(5, 3)
;WITH CTE_Tree AS
(
SELECT
id,
ancestor_id,
1 AS lvl,
id AS base
FROM
@test
WHERE
id = @id
UNION ALL
SELECT
C.id,
C.ancestor_id,
P.lvl + 1 AS lvl,
P.base AS base
FROM
CTE_Tree P
INNER JOIN @test C ON C.ancestor_id = P.id
WHERE
lvl <= COALESCE(@j, 9999)
)
SELECT
id,
ancestor_id
FROM
CTE_Tree
WHERE
lvl BETWEEN @i AND COALESCE(@j, 9999)