【问题标题】:Recursive CTE query in SQL ServerSQL Server 中的递归 CTE 查询
【发布时间】:2013-11-05 20:26:24
【问题描述】:

我已经在此站点上查看了许多递归 CTE 示例,并尝试将其应用于我自己的数据。我似乎比大多数例子有更多的连接,但我想我已经到了。我需要帮助的问题是我收到一条错误消息:

语句终止。在语句完成之前,最大递归 100 已用完。

我已经运行了 CTE 的第一个 select 语句,并且我重复运行了第二个 select 语句(具有不同的实际职位代码),对于这个员工有六个级别,所以我不明白为什么会出现错误。

我怀疑的一个领域是我必须应用标准“relationship_type_id = 0”,因为这是“报告对象”关系类型。我曾尝试将其设为左外连接,但不允许这样做。这意味着我没有使用此查询获得*别的经理(即自己没有经理的人)。

我已经在下面发布了代码,我们将不胜感激。

WITH EmployeeHierarchy (EmployeeID, LastName, FirstName, PositionCode, ReportsTo, HierarchyLevel) AS 
(
   SELECT 
      p.employee_id as EmployeeID,
      p.last_name as LastName,
      p.first_name as FirstName,
      pos.position_code as PositionCode,
      r.to_position_code as ReportsTo,
      1 as HierarchyLevel
   FROM 
       --JOIN: Personal details
       dbo.person p
   --JOIN: Employment links a person to a post (could have more than one)
   INNER JOIN 
       dbo.employment e ON e.employee_id = p.employee_id
   --JOIN: details of the position held
   INNER JOIN 
       dbo.position pos ON pos.position_code = e.position_code
   --JOIN: Relationships between the positions, one position reports to another position etc.
   --      There are several 'relationship types', we are only interested in relationship_type_id = 0 
   --      as this is the 'Reports to' relationship code.  Others types include 'Managed by' etc.
   INNER JOIN 
       dbo.relationship r ON r.from_position_code = pos.position_code AND r.relationship_type_id = 0
   WHERE 
       --CRITERIA: Use my employee Id as a starting point for testing
       p.employee_id = '10076395'

   UNION ALL

   -- Recursive step
   SELECT 
       p2.employee_id as EmployeeID,
       p2.last_name as LastName,
       p2.first_name as FirstName,
       pos2.position_code as PositionCode,
       r2.to_position_code as ReportsTo,
       eh.HierarchyLevel + 1 AS HierarchyLevel
   FROM 
       dbo.person p2
   INNER JOIN 
       dbo.employment e2 ON e2.employee_id = p2.employee_id
   INNER JOIN 
       dbo.position pos2 ON pos2.position_code = e2.position_code
   INNER JOIN 
       dbo.relationship r2 ON r2.from_position_code = pos2.position_code AND r2.relationship_type_id = 0
   --JOIN: Link this query back to the base query
   INNER JOIN 
       EmployeeHierarchy eh ON r2.from_position_code = eh.PositionCode
)
SELECT *
FROM EmployeeHierarchy
ORDER BY HierarchyLevel, LastName, FirstName 

【问题讨论】:

  • 我不确定数据的结构是什么,但您没有在查询的递归部分使用to_position_code,我猜这是您想要的下一个级别得到。
  • 我还没有仔细查看您的代码,但是由于这可能是您数据中的循环引用,因此我建议您发布足够的示例数据来重现该问题。
  • 尝试将 where HierarchyLevel < 3 添加到 CTE 的递归部分。这应该让您查看部分结果,以便您可以看到它的前进方向。

标签: sql sql-server


【解决方案1】:

试试这个。

我已将复杂的联接移至单独的 CTE,以使递归部分尽可能干净和简单。如果没有别的,这种方法应该可以帮助您查明您的问题。

; WITH employees AS (
  SELECT person.employee_id
       , person.last_name
       , person.first_name
       , position.position_code
       , relationship.to_position_code
  FROM   dbo.person
   INNER
    JOIN dbo.employment
      ON employment.employee_id = person.employee_id
   INNER
    JOIN dbo.position
      ON position.position_code = employment.position_code
   INNER
    JOIN dbo.relationship
      ON relationship.from_position_code = position.position_code
     AND relationship.relationship_type_id = 0
)
, recursive_bit AS (
  SELECT employee_id
       , last_name
       , first_name
       , position_code
       , to_position_code
  FROM   employees
  WHERE  employee_id = '10076395'

    UNION ALL

      SELECT employees.employee_id
           , employees.last_name
           , employees.first_name
           , employees.position_code
           , employees.to_position_code
      FROM   recursive_bit
       INNER
        JOIN employees
          ON employees.position_code = recursive_bit.to_position_code
)
SELECT *
FROM   recursive_bit

【讨论】:

    【解决方案2】:

    请尝试:

    WITH EmployeeHierarchy (EmployeeID, LastName, FirstName, PositionCode, ReportsTo, HierarchyLevel) AS 
    (
    SELECT 
        p.employee_id as EmployeeID,
        p.last_name as LastName,
        p.first_name as FirstName,
        pos.position_code as PositionCode,
        r.to_position_code as ReportsTo,
        1 as HierarchyLevel
    FROM 
        --JOIN: Personal details
        dbo.person p
    
        --JOIN: Employment links a person to a post (could have more than one)
        INNER JOIN dbo.employment e
        ON e.employee_id = p.employee_id
    
        --JOIN: details of the position held
        INNER JOIN dbo.position pos 
        ON pos.position_code = e.position_code
    
        --JOIN: Relationships between the positions, one position reports to another position etc.
        --      There are several 'relationship types', we are only interested in relationship_type_id = 0 
        --      as this is the 'Reports to' relationship code.  Others types include 'Managed by' etc.
        INNER JOIN dbo.relationship r
        ON  r.from_position_code = pos.position_code
            and r.relationship_type_id = 0
    WHERE 
        --CRITERIA: Use my employee Id as a starting point for testing
        p.employee_id = '10076395'
    
    UNION ALL
    -- Recursive step
    SELECT 
        p2.employee_id as EmployeeID,
        p2.last_name as LastName,
        p2.first_name as FirstName,
        pos2.position_code as PositionCode,
        r2.to_position_code as ReportsTo,
        eh.HierarchyLevel + 1 AS HierarchyLevel
     FROM 
        dbo.person p2
    
        INNER JOIN dbo.employment e2
        ON e2.employee_id = p2.employee_id
    
        INNER JOIN dbo.position pos2 
        ON pos2.position_code = e2.position_code
    
        INNER JOIN dbo.relationship r2
        ON  r2.from_position_code = pos2.position_code
            and r2.relationship_type_id = 0
    
        --JOIN: Link this query back to the base query
        INNER JOIN EmployeeHierarchy eh 
        ON r2.from_position_code = eh.ReportsTo
    )
    SELECT *
    FROM EmployeeHierarchy
    ORDER BY HierarchyLevel, LastName, FirstName 
    

    【讨论】:

    • 好发现 yswai1986!谢谢,这是一种享受:-)
    • Szymon,你当然也是对的!谢谢大家,非常迅速的反应,这是我第一次发帖 - 我印象非常深刻!