SQL Server CTE and recursion example

后端 未结 4 1020
臣服心动
臣服心动 2020-11-22 07:03

I never use CTE with recursion. I was just reading an article on it. This article shows employee info with the help of Sql server CTE and recursion. It is basically showing

相关标签:
4条回答
  • 2020-11-22 07:33

    I haven't tested your code, just tried to help you understand how it operates in comment;

    WITH
      cteReports (EmpID, FirstName, LastName, MgrID, EmpLevel)
      AS
      (
    -->>>>>>>>>>Block 1>>>>>>>>>>>>>>>>>
    -- In a rCTE, this block is called an [Anchor]
    -- The query finds all root nodes as described by WHERE ManagerID IS NULL
        SELECT EmployeeID, FirstName, LastName, ManagerID, 1
        FROM Employees
        WHERE ManagerID IS NULL
    -->>>>>>>>>>Block 1>>>>>>>>>>>>>>>>>
        UNION ALL
    -->>>>>>>>>>Block 2>>>>>>>>>>>>>>>>>    
    -- This is the recursive expression of the rCTE
    -- On the first "execution" it will query data in [Employees],
    -- relative to the [Anchor] above.
    -- This will produce a resultset, we will call it R{1} and it is JOINed to [Employees]
    -- as defined by the hierarchy
    -- Subsequent "executions" of this block will reference R{n-1}
        SELECT e.EmployeeID, e.FirstName, e.LastName, e.ManagerID,
          r.EmpLevel + 1
        FROM Employees e
          INNER JOIN cteReports r
            ON e.ManagerID = r.EmpID
    -->>>>>>>>>>Block 2>>>>>>>>>>>>>>>>>
      )
    SELECT
      FirstName + ' ' + LastName AS FullName,
      EmpLevel,
      (SELECT FirstName + ' ' + LastName FROM Employees
        WHERE EmployeeID = cteReports.MgrID) AS Manager
    FROM cteReports
    ORDER BY EmpLevel, MgrID
    

    The simplest example of a recursive CTE I can think of to illustrate its operation is;

    ;WITH Numbers AS
    (
        SELECT n = 1
        UNION ALL
        SELECT n + 1
        FROM Numbers
        WHERE n+1 <= 10
    )
    SELECT n
    FROM Numbers
    

    Q 1) how value of N is getting incremented. if value is assign to N every time then N value can be incremented but only first time N value was initialize.

    A1: In this case, N is not a variable. N is an alias. It is the equivalent of SELECT 1 AS N. It is a syntax of personal preference. There are 2 main methods of aliasing columns in a CTE in T-SQL. I've included the analog of a simple CTE in Excel to try and illustrate in a more familiar way what is happening.

    --  Outside
    ;WITH CTE (MyColName) AS
    (
        SELECT 1
    )
    -- Inside
    ;WITH CTE AS
    (
        SELECT 1 AS MyColName
        -- Or
        SELECT MyColName = 1  
        -- Etc...
    )
    

    Excel_CTE

    Q 2) now here about CTE and recursion of employee relation the moment i add two manager and add few more employee under second manager then problem start. i want to display first manager detail and in the next rows only those employee details will come those who are subordinate of that manager

    A2:

    Does this code answer your question?

    --------------------------------------------
    -- Synthesise table with non-recursive CTE
    --------------------------------------------
    ;WITH Employee (ID, Name, MgrID) AS 
    (
        SELECT 1,      'Keith',      NULL   UNION ALL
        SELECT 2,      'Josh',       1      UNION ALL
        SELECT 3,      'Robin',      1      UNION ALL
        SELECT 4,      'Raja',       2      UNION ALL
        SELECT 5,      'Tridip',     NULL   UNION ALL
        SELECT 6,      'Arijit',     5      UNION ALL
        SELECT 7,      'Amit',       5      UNION ALL
        SELECT 8,      'Dev',        6   
    )
    --------------------------------------------
    -- Recursive CTE - Chained to the above CTE
    --------------------------------------------
    ,Hierarchy AS
    (
        --  Anchor
        SELECT   ID
                ,Name
                ,MgrID
                ,nLevel = 1
                ,Family = ROW_NUMBER() OVER (ORDER BY Name)
        FROM Employee
        WHERE MgrID IS NULL
    
        UNION ALL
        --  Recursive query
        SELECT   E.ID
                ,E.Name
                ,E.MgrID
                ,H.nLevel+1
                ,Family
        FROM Employee   E
        JOIN Hierarchy  H ON E.MgrID = H.ID
    )
    SELECT *
    FROM Hierarchy
    ORDER BY Family, nLevel
    

    Another one sql with tree structure

    SELECT ID,space(nLevel+
                        (CASE WHEN nLevel > 1 THEN nLevel ELSE 0 END)
                    )+Name
    FROM Hierarchy
    ORDER BY Family, nLevel
    
    0 讨论(0)
  • 2020-11-22 07:33

    The execution process is really confusing with recursive CTE, I found the best answer at https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx and the abstract of the CTE execution process is as below.

    The semantics of the recursive execution is as follows:

    1. Split the CTE expression into anchor and recursive members.
    2. Run the anchor member(s) creating the first invocation or base result set (T0).
    3. Run the recursive member(s) with Ti as an input and Ti+1 as an output.
    4. Repeat step 3 until an empty set is returned.
    5. Return the result set. This is a UNION ALL of T0 to Tn.
    0 讨论(0)
  • 2020-11-22 07:42

    Would like to outline a brief semantic parallel to an already correct answer.

    In 'simple' terms, a recursive CTE can be semantically defined as the following parts:

    1: The CTE query. Also known as ANCHOR.

    2: The recursive CTE query on the CTE in (1) with UNION ALL (or UNION or EXCEPT or INTERSECT) so the ultimate result is accordingly returned.

    3: The corner/termination condition. Which is by default when there are no more rows/tuples returned by the recursive query.

    A short example that will make the picture clear:

    ;WITH SupplierChain_CTE(supplier_id, supplier_name, supplies_to, level)
    AS
    (
    SELECT S.supplier_id, S.supplier_name, S.supplies_to, 0 as level
    FROM Supplier S
    WHERE supplies_to = -1    -- Return the roots where a supplier supplies to no other supplier directly
    
    UNION ALL
    
    -- The recursive CTE query on the SupplierChain_CTE
    SELECT S.supplier_id, S.supplier_name, S.supplies_to, level + 1
    FROM Supplier S
    INNER JOIN SupplierChain_CTE SC
    ON S.supplies_to = SC.supplier_id
    )
    -- Use the CTE to get all suppliers in a supply chain with levels
    SELECT * FROM SupplierChain_CTE
    

    Explanation: The first CTE query returns the base suppliers (like leaves) who do not supply to any other supplier directly (-1)

    The recursive query in the first iteration gets all the suppliers who supply to the suppliers returned by the ANCHOR. This process continues till the condition returns tuples.

    UNION ALL returns all the tuples over the total recursive calls.

    Another good example can be found here.

    PS: For a recursive CTE to work, the relations must have a hierarchical (recursive) condition to work on. Ex: elementId = elementParentId.. you get the point.

    0 讨论(0)
  • 2020-11-22 07:49
        --DROP TABLE #Employee
        CREATE TABLE #Employee(EmpId BIGINT IDENTITY,EmpName VARCHAR(25),Designation VARCHAR(25),ManagerID BIGINT)
    
        INSERT INTO #Employee VALUES('M11M','Manager',NULL)
        INSERT INTO #Employee VALUES('P11P','Manager',NULL)
    
        INSERT INTO #Employee VALUES('AA','Clerk',1)
        INSERT INTO #Employee VALUES('AB','Assistant',1)
        INSERT INTO #Employee VALUES('ZC','Supervisor',2)
        INSERT INTO #Employee VALUES('ZD','Security',2)
    
    
        SELECT * FROM #Employee (NOLOCK)
    
        ;
        WITH Emp_CTE 
        AS
        (
            SELECT EmpId,EmpName,Designation, ManagerID
                  ,CASE WHEN ManagerID IS NULL THEN EmpId ELSE ManagerID END ManagerID_N
            FROM #Employee  
        )
        select EmpId,EmpName,Designation, ManagerID
        FROM Emp_CTE
        order BY ManagerID_N, EmpId
    
    0 讨论(0)
提交回复
热议问题