CTE查询:如何使它们按顺序排列

时间:2013-09-12 17:44:03

标签: sql-server common-table-expression

我有一个表格,以常规的分层方式存储公司信息及其母公司,包括companyid,parentid和name。

我只是在Sql Server中学习CTE查询并编写此查询

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

这样可以正常工作,除了它首先列出ID = 9的Child,然后列出第一级子级然后级别2 ......依此类推,但我需要的是将Child数据放在其父级之下,所以

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

有可能吗?因为如果没有,那么我必须在我正在使用的C#代码中递归地执行它。

我也试试这个

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 

但如果任何Level有超过9条记录,则失败。

4 个答案:

答案 0 :(得分:2)

试试这个解决方案:

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;

结果:

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

注意:SQL Azure Supports Hierarchyid Data Type

答案 1 :(得分:0)

嗯,事情是,你没有ORDER BY子句。

为什么不至少尝试

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

也就是说,显示/ UI分区可能应该由UI输出,而不是您的查询。

这几乎看起来你希望在TreeView中使用它来显示它。

答案 2 :(得分:0)

好的,最后我找到了一个问题的解决方案。为了得到评论家,如果我在这里帮助其他人,那就是

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  

现在,解释如下:

  1. 我添加了SQL Server的ROW_NUMBER函数,这只是将计数器添加到每行查询中,因此它将单独的计数器添加到Anchor查询和递归查询。
  2. 但是由于我们必须安排它们,为了将Parent / Anchor查询值附加到Child,所以Anchor查询转为1,2,3 ..但是孩子去11,12 ... 21 ......
  3. 然后我把它们作为字符串投射,因为在字符串顺序中你将有1,2,21,3而不是1,2,3,21 ..所以这对我来说很好。
  4. 已知问题:当您点击Anchor查询输出>时,它会被击败。 10行,或者实际上任何超过10行的行,然后锚点查询将ID指定为11,子进程为111并混淆输出。

    上述问题的解决方案:我修改我的查询以使用LEFT并附加000,所以如果我看到我最多可以有100个孩子,如果你看到4就把3个零然后使用0000并在查询中改变3到4。

    但是:我强烈推荐上面的答案,因为这样做。

答案 3 :(得分:0)

我想分享一下

如果你想订购de data ...字母和子数据就在他们的父母之下..创建一个baseCTE,使用row_number而不是CompanyID,从Base CTE调用Anchor查询

BASE CTE

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

锚定查询

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

递归查询

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