SQL Server - 如何管理表中的分层数据?

时间:2009-09-07 18:25:12

标签: sql sql-server tsql sql-server-2000

我使用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位父母?

没有循环可以吗?

可能不是。

6 个答案:

答案 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

的嵌套集模型

甚至更好关闭表模型