【问题标题】:CTE Query: How to make them in orderCTE 查询:如何按顺序制作它们
【发布时间】:2015-07-22 02:54:27
【问题描述】:

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

我刚刚在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 的子级,然后列出 1 级子级,然后列出 2 级 .. 等等,但我需要的是让子级数据位于其父级之下,所以

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 

但如果任何级别的记录超过 9 条,它就会失败。

【问题讨论】:

  • 1) 哪个 SQL Server 版本? 2)WHERE ParentCompanyID in (9) 谓词的目的是什么?是否要显示母公司 9 的所有子公司?
  • 我们将 SQL Azure 作为我们的服务器。是的,我们需要所有父 ID = 9 的子节点,它可以为 0 来显示所有 [我们使用 0 作为基本级别父节点]。

标签: sql-server common-table-expression


【解决方案1】:

试试这个解决方案:

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

【讨论】:

  • 这看起来很棒,我将使用它。我不知道 HireracyID,今天要学习的新东西。顺便说一句,我修改了自己的解决方案,也适用于 999 个孩子:)。但你的干净得多。
  • @SumitGupta:我用 SQL Server 2008 R2 测试了这个解决方案。
  • 我将在 5 分钟内测试 azure
【解决方案2】:

嗯,东西 ios,你没有 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 中显示它。

【讨论】:

  • 我添加了订单,但它只显示第 1 级后跟第 2 级后跟第 3 级,没有排列它们。作为我的愿望输出。
【解决方案3】:

好的,我终于找到了解决问题的方法。为了得到批评,如果我在这里帮助其他人是对的,那就是

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 函数,这只是将计数器添加到查询的每一行,因此它将单独的计数器添加到锚查询和递归查询。
  2. 但由于我们必须安排它们,因此我将父/锚查询值附加到子级,因此锚查询为 1、2、3.. 但子级为 11、12 ... 21 ...
  3. 然后我将它们转换为字符串,因为在字符串顺序中,您将拥有 1、2、21、3 而不是 1、2、3、21 .. 所以这对我来说很好。

已知问题:当您点击 Anchor 查询输出 > 10 行或事实上任何超过 10 行的行时,它会被打倒,因为然后锚查询将 ID 设为 11,而 child 为 111 并混淆输出。

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

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

【讨论】:

    【解决方案4】:

    我想分享这个

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

    基础 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'/'
    

    【讨论】:

      猜你喜欢
      • 2019-09-03
      • 1970-01-01
      • 1970-01-01
      • 2017-03-17
      • 1970-01-01
      • 2017-03-29
      • 2016-11-01
      • 2010-11-18
      • 1970-01-01
      相关资源
      最近更新 更多