我使用SQL Server 2000。
假设我有两个表,如下所示:
Area
----------------------------------
ID| Name | HierarchyLevel
----------------------------------
1 | World | 1
2 | America| 2
3 | Europe | 2
4 | Africa | 2
5 | USA | 3
和
AreaHierarchy
------------------------
ID | ParentID | ChildID
------------------------
1 | 1 | 2
2 | 1 | 3
3 | 1 | 4
4 | 2 | 5
其中
AreaHierarchy.ParentID和AreaHierarchy.ChildID是Area.ID的FK
如何找到美国的第n位父母?
没有循环可以吗?
可能不是。
答案 0 :(得分:5)
最好的办法是在你的第二个表中添加额外的字段,即调用ie。 Parents
只会将父ID存储在字符串中,如:
AreaHierarchy
------------------------------------
ID | ParentID | ChildID | Parents
------------------------------------
1 | 1 | 2 | 1/
2 | 1 | 3 | 1/
3 | 1 | 4 | 1/
4 | 2 | 5 | 1/2/
通过这种方式,您可以轻松访问分支中的任何父级,而无需递归或任何其他复杂的过程。处理成本非常小,您只需复制父级Parents
值并再添加一个ID。而且由于您可能需要阅读更多而不是写入/更新,这是解决您问题的最佳方法。
如果我是你,我会为你拥有的数据保留一张表。将两个表合并为一个。也可以根据Parents
varchar值中的计数斜杠计算级别,但我不建议这样做。
如果您的数据主要是读/写且更新更少,则此结构确实非常高效。但是,如果您的表执行的更新比读/写更多,则应避免使用此技术。为什么?想象一下,你有一棵很深的树,有很多孩子。在根目录附近将某个节点的父节点更改为高位意味着您应该更新整个子树节点的Parents
。
答案 1 :(得分:1)
应该工作
CREATE PROCEDURE find_nth_parent
@id INT,
@level INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @counter INT
SET @counter = 1
DECLARE @currentItem INT
DECLARE @currentItemNew INT
SET @currentItem = @id
WHILE @counter <= @level
BEGIN
SET @currentItemNew = NULL
SELECT @currentItemNew = ParentID FROM AreaHierarchy WHERE ChildId = @currentItem
IF @currentItemNew IS NULL
BEGIN
SELECT NULL
RETURN
END
SET @currentItem = @currentItemNew
SET @counter = @counter + 1
END
SELECT @currentItem
END
调用
EXEC find_nth_parent 5,2
返回1表示“世界”(第二个父母),调用
EXEC find_nth_parent 5,1
返回2,表示“美国”(第一父母)。
希望有所帮助
答案 2 :(得分:1)
你可以使用递归。如果您有SQL Server 2005或更高版本,则可以使用公用表表达式。如果不是,您实际上需要使用用户定义函数。
这样做的UDF的一个例子可能是......
CREATE FUNCTION get_nth_parent(area_id AS INT, n as INT)
RETURNS INT
AS
IF (n = 0) RETURN area_id
DECLARE @return INT
SELECT
@return = dbo.get_nth_parent(AreaHierarchy.ParentID, n-1)
FROM
AreaHierarchy
WHERE
ChildID = area_id
RETURN @return
使用Common Table Experessions的示例可能是......
DECLARE @hierarchy TABLE (
parent_id INT,
child_id INT
)
INSERT INTO @hierarchy SELECT 1,2
INSERT INTO @hierarchy SELECT 1,3
INSERT INTO @hierarchy SELECT 1,4
INSERT INTO @hierarchy SELECT 2,5
;WITH
relative_distance (
child_id,
parent_id,
distance
)
AS
(
SELECT
child_id,
parent_id,
1
FROM
@hierarchy
UNION ALL
SELECT
[relative_distance].child_id,
[hierarchy].parent_id,
[relative_distance].distance + 1
FROM
[relative_distance]
INNER JOIN
@hierarchy AS [hierarchy]
ON [hierarchy].child_id = [relative_distance].parent_id
)
SELECT
parent_id
FROM
[relative_distance]
WHERE
child_id = 5
AND distance = 2
答案 3 :(得分:1)
在SQL Server 2005+中,您将在函数中使用CTE:
create function get_parent(@child as int, @parent_level as int)
returns int
as
begin
declare @parent int
;with parentage as (
select
h.parent_id,
h.child_id,
0 as level
from
areahierarchy h
where
h.child_id = @child
union all
select
h.parent_id,
h.child_id,
p.level + 1 as level
from
areahierarchy h
inner join parentage p on
h.parent_id = p.child_id
where
p.level < @parent_level
)
select @parent = p.child_id from parentage p
where level = (select max(level) from parentage)
return @parent
end
答案 4 :(得分:0)
我知道您希望支持SQL Server 2000,但我认为应该注意SQL Server 2008 Hierarchy ID函数GetAncestor()完全符合您的要求。
答案 5 :(得分:0)
您可以使用Joe Celko https://en.wikipedia.org/wiki/Nested_set_model
的嵌套集模型甚至更好关闭表模型