CTE Query: How to make them in order

与世无争的帅哥 提交于 2019-12-12 09:01:08

问题


I have a table which stores company information and their parent company in a regular hierarchical manner, with companyid, parentid and name.

I just learn CTE query in Sql Server and write this query

WITH tableR (ParentCompanyID, CompanyID, Levels)
AS
(
-- Anchor member definition
    SELECT e.ParentCompanyID, e.CompanyID, 0 As Levels
    FROM tblCompany AS e   
    WHERE ParentCompanyID in (9)
    UNION ALL
-- Recursive member definition
    SELECT e.ParentCompanyID, e.CompanyID, Levels  + 1
    FROM tblCompany AS e   
    INNER JOIN tableR AS d
        ON e.ParentCompanyID = d.CompanyID
)
-- Statement that executes the CTE
SELECT tabler.Levels, tableR.CompanyID, (left('--------------', (tabler.Levels* 2)) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR  Left join tblcompany c on tableR.CompanyId=c.CompanyID

This works fine, except that it first list the Child of ID=9, then it list 1st level child and then level 2 .. and so on, but what I need is to have Child data come just under their parent, so

L0
  L1
    L2
  L1-1
    L2-1
 ....

Is it possible to do? Because if not then I have to do it recursively in C# code I am using.

I try this as well

WITH tableR (ParentCompanyID, CompanyID, Levels, RowNumber)
AS
(
-- Anchor member definition
    SELECT e.ParentCompanyID, e.CompanyID, 1 As Levels, CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)) as RowNumber
    FROM tblCompany AS e   
    WHERE ParentCompanyID in (9)
    UNION ALL
-- Recursive member definition
    SELECT e.ParentCompanyID, e.CompanyID, Levels  + 1, CAST(Concat(d.RowNumber, CAST((Row_Number() Over (Order by e.CompanyName) ) as VARCHAR(MAX)) ) as VARCHAR(MAX)) as RowNumber
    FROM tblCompany AS e   
    INNER JOIN tableR AS d
        ON e.ParentCompanyID = d.CompanyID
)
-- Statement that executes the CTE
SELECT tabler.Levels, RowNumber, tableR.CompanyID, (left('--------------', ((tabler.Levels - 1)* 2 )) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR  Left join tblcompany c on tableR.CompanyId=c.CompanyID order by RowNumber 

But it fails with if any Level has more than 9 records.


回答1:


Try this solution:

DECLARE @Company TABLE
(
    CompanyID INT PRIMARY KEY,
    Name NVARCHAR(50) NOT NULL,
    ParentCompanyID INT NULL
);
INSERT @Company (CompanyID,Name,ParentCompanyID)
VALUES 
(8,N'Tomaten',NULL),
(9,N'NON ĂNŞI chars',NULL),
(10,N'Bananen',NULL),
(11,N'Child #1',9),
(12,N'Child #2',9),
(13,N'Child #1.1',11),
(14,N'Child #1.2',11);

DECLARE @ParentCompanyID INT = 9;
WITH RecComp
AS
(
    SELECT  crt.CompanyID,
            crt.Name,
            crt.ParentCompanyID,
            1 AS Lvl,
            N'/' + CONVERT(NVARCHAR(4000),crt.CompanyID) + N'/' AS CompanyNode_AsChar
    FROM    @Company crt
    WHERE   crt.ParentCompanyID = @ParentCompanyID
    UNION ALL
    SELECT  cld.CompanyID,
            cld.Name,
            cld.ParentCompanyID,
            prt.Lvl + 1,
            prt.CompanyNode_AsChar + CONVERT(NVARCHAR(4000), cld.CompanyID) + N'/'
    FROM    RecComp prt -- parent
    INNER JOIN @Company cld ON prt.CompanyID = cld.ParentCompanyID
)
SELECT  *,
        CONVERT(HIERARCHYID, CompanyNode_AsChar) AS CompanyNode
FROM    RecComp
ORDER BY CompanyNode;

Results:

CompanyID Name       ParentCompanyID Lvl CompanyNode_AsChar CompanyNode
--------- ---------- --------------- --- --------------------- -----------
11        Child #1   9               1   /11/                  0xAE
13        Child #1.1 11              2   /11/13/               0xAF6C
14        Child #1.2 11              2   /11/14/               0xAF74
12        Child #2   9               1   /12/                  0xB2

Note: SQL Azure Supports Hierarchyid Data Type




回答2:


Well, the thing ios, you have no ORDER BY clause.

Why not at least try

-- Statement that executes the CTE
SELECT tabler.Levels, tableR.CompanyID, (left('--------------', (tabler.Levels* 2)) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR  Left join tblcompany c on tableR.CompanyId=c.CompanyID
ORDER BY tableR.Levels

That said, the display/UI sectioin should probably be taken car of by the UI output, and not by your query.

This almost seems like you wish to diusplay it in a TreeView rather.




回答3:


Okay, finally I found a solution to issue. In order to get critics and if I am right to help other here it is

WITH tableR (ParentCompanyID, CompanyID, Levels, RowNumber, RowNumber2)
AS
(
-- Anchor member definition
    SELECT e.ParentCompanyID, e.CompanyID, 1 As Levels, CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)) as RowNumber,
    CAST(
     (Left('000', 3-Len(CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)))) + CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx))) 
     As VARCHAR(MAX)
     ) AS RowNumber2
    FROM tblCompany AS e   
    WHERE ParentCompanyID in (370)
    UNION ALL
-- Recursive member definition
    SELECT e.ParentCompanyID, e.CompanyID, Levels  + 1, CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)) as RowNumber1,
    CAST(
        Concat(d.RowNumber2, 
         Left('000', 3-Len(CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx)))),
          CAST((Row_Number() Over (Order by e.CompanyName) ) as Varchar(MAx))
        ) as VARCHAR(MAX)) as RowNumber2

    FROM tblCompany AS e   
    INNER JOIN tableR AS d
        ON e.ParentCompanyID = d.CompanyID

)
-- Statement that executes the CTE
SELECT tabler.Levels, RowNumber, RowNumber2,  tableR.CompanyID, (left('--------------', ((tabler.Levels - 1)* 2 )) + c.CompanyName) as CName,c.ParentCompanyID
FROM tableR  Left join tblcompany c on tableR.CompanyId=c.CompanyID order by RowNumber2, CName  

Now, here is the explanation:

  1. I add a ROW_NUMBER Function of SQL Server this simply add the counter to each row of query, so it add seperate counter to Anchor query and Recursive query.
  2. But as we have to arrange them, in order I append Parent/Anchor query value to Child, so Anchor query goes 1, 2, 3.. but child goes 11, 12 ... 21 ...
  3. Then I Cast them as String, because in String Order you will have 1, 2, 21, 3 rather than 1, 2, 3, 21 .. so that works fine for me.

Problem Known: it get bowled over when you hit Anchor query output > 10 rows, or infact any row more than 10 rows, as then anchor query give ID as 11, and child goes 111 and confuse the output.

Solution for above problem: I modify my query to use LEFT and append 000, so if I see that I can max of 100 child I put 3 zero if you see 4 then use 0000 and change 3 to 4 in query.

BUT: I strongly recommend answer above as that is the way to do it.




回答4:


I would like to share this

if you want to order de data... alphabetic and Child data come just under their parent.. create a baseCTE, use row_number instead of CompanyID, call the Anchor query from Base CTE

BASE CTE

ROW_NUMBER() OVER ( PARTITION BY ParentCompanyID ORDER BY CompanyName) as [row_number]

Anchor query

N'/' + CONVERT(NVARCHAR(4000),[row_number]) + N'/' AS CompanyNode_AsChar

Recursive query

prt.CompanyNode_AsChar + CONVERT(NVARCHAR(4000), [row_number]) + N'/'


来源:https://stackoverflow.com/questions/18770958/cte-query-how-to-make-them-in-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!