如何检索所需的记录?

时间:2016-08-02 16:43:16

标签: sql sql-server database

输入表:区域

    +---------------+---------------+---------- +-----------+
    | Child         | Parent        | Level     |  levelname|
    +---------------+---------------+---------- +-----------+
    | All Region    | All Region    | 1         |  national |
    | Africa Region | All Region    | 2         |   region  |
    | America       | All Region    | 2         |   region  |
    | Asia          | All Region    | 2         |   region  |
    | Europe Region | All Region    | 2         |   region  |
    | Africa        | Africa Region | 3         | Subregion |
    | Asia Pacific  | Asia          | 3         | Subregion |
    | Europe        | Europe Region | 3         | Subregion |
    | North America | America       | 3         | Subregion |
    | South America | America       | 3         | Subregion | 
    | Argentina     | South America | 4         |   Country |
    | Australia     | Asia Pacific  | 4         |   Country |
    | Pakistan      | Asia Pacific  | 4         |   Country | 
    | South Africa  | Africa        | 4         |   Country |
    | Tunisia       | Africa        | 4         |   Country | 
    | Uruguay       | South America | 4         |   Country |
    +-------------------------------------------------------+

此处,区域为4级

  • 所有地区
  • 区域
  • 子区域
  • 国家

    他们拥有0,1,2和3个祖先,例如一个国家有子区域,地区和所有地区作为祖先,假设我们给予"乌拉圭" ,然后输出将是南美洲,美国,所有地区。

现在,我需要对此表进行查询,该查询将检索给定"孩子的所有祖先"

1 个答案:

答案 0 :(得分:4)

你最好的选择是递归CTE:

With recRegions AS
(
    /*Recursive Seed*/
    SELECT
        Child,
        Parent,
        Level,
        0 as Depth,
        CAST(Child as VARCHAR(5000)) as Path
    FROM
        Regions
    WHERE 
        Child=<WhateverChildYouAreWanting>

    UNION ALL

    /*Recursive Term*/
    SELECT
        Regions.Child,
        Regions.Parent,
        Region.Level,
        recRegions.Depth + 1,
        recRegions.Path || '>' || Region.Child
    FROM
        recRegions
        INNER JOIN Regions on
            recRegions.parent = Regions.Child
    Where recRegions.Depth < 10
)

Select Parent as Ancestors FROM recRegions;

递归查询最初可能有点棘手,但是如果你分解它,那就有意义了:

  1. 递归种子 - 这是我们获得第一个学期的部分。在您的情况下,我们只需要记录Child所在国家/地区的记录。
  2. 递归术语 - 这是查询引用自身的部分。它将递归CTE recRegions连接到您的Region表,将子连接到父级。数据库将触及此递归术语,直到没有更多记录返回,这意味着我们已经一直爬上你的层次结构。
  3. 最终的select语句只是从递归查询中拉回记录。你想要所有的祖先,这就是所有Parent字段记录。
  4. 通常当你看到一个布局为child | parent | attributes | of | that | relationship的桌子时,你可以转向超强大的递归CTE来快速理解它。

    正如@dnoeth在你的Q评论中提到的,你也可以将Regions表连接到自己4次,因为你的层次结构似乎只有4个深度。递归查询并不关心深度,因此如果您为层次结构添加更多深度,则不必编辑SQL来拉动祖先。

    更新以添加&#34;深度&#34;字段跟踪递归并在10之后停止。还添加了一个&#34;路径&#34;字段,用于跟踪从子级构建的层次结构。如果您的层次结构循环存在问题(向子级报告的子级报告给子级导致无限循环),则可以使用以下SQL语句而不是上面的SELECT parent FROM版本:

     SELECT * FROM recRegions;
    

    现在,您将看到层次结构中每个节点的路径和深度,以便您可以修复数据,或者递归CTE以避免循环。