如何从以下查询中获取分层值?

AnO*_*oul 8 cte t-sql subquery sql-server-2012

我有一个名为的表Category,其中有一列名为CategoryID. 同一个表中有一个引用列,称为fParentCategoryID

我需要将所有类别 ID 及其子类别 ID 以逗号分隔。例如 -如果 10 的父类别 ID 为 1,如果 20 的父类别 ID 为 10,那么当我打印类别 ID 20 时,我需要以逗号分隔值打印 1 和 10 作为其父项。

我尝试了以下查询,但我得到NULLParChild列。请帮忙。

;WITH
  cteReports 
  AS
(
SELECT c.CategoryID,
       c.fParentCategoryID,
       [level] = 1,
       ParChild=cast(CAST(c.fParentCategoryID AS VARCHAR(200)) + ',' + CAST(c.CategoryID AS VARCHAR(200)) AS VARCHAR(MAX))
FROM   retail.Category c
WHERE c.fParentCategoryID is NULL
UNION ALL
SELECT c.CategoryID,
       c.fParentCategoryID,
       [level] + 1,
       ParChild = ParChild + ',' + CAST(c.CategoryID AS VARCHAR(200))
FROM   retail.Category c
        JOIN cteReports r
            ON  c.fParentCategoryID = r.CategoryID

)

SELECT *
FROM   cteReports cr 
Run Code Online (Sandbox Code Playgroud)

使用此脚本创建和填充表。 (注意:问题正文有 30K 的限制..所以我不得不使用 pastebin 复制你的代码并引用它)

sev*_*ist 3

我能够用您的示例数据复制您的结果。

您的问题是,在递归 CTE(第一个 select 语句)的“基本”情况下,您将获取 fParentCategoryID 为 null 的记录,并将 fParentCategoryID 转换为准备附加“子项”的字符列。然而,在此阶段“字符串”仍然是 NULL 值(尝试使用 SELECT CAST(NULL AS VARCHAR(200)) 等)。

然后,第二个 select 语句尝试将其他字符串值附加到 NULL,但默认情况下,数据库选项“concat null 产生 null”表示,如果您尝试将任何内容连接到 NULL 值,那么您仍然只会得到 NULL - 而不是将其视为一个空字符串。

您可以为此查询设置 CONCAT_NULL_YIELDS_NULL OFF,尽管这已被弃用,并且最终将在 SQL Server 的未来版本中删除(因此您可能不应该将其添加到生产代码中!)

更好的方法是在第一个 select 语句中,不要将 fParentCategoryID 转换为字符串,而只需转换 CategoryID - 我们已经知道父级应该为空,因为它们是 NULL。

SELECT c.CategoryID,
   c.fParentCategoryID,
   [level] = 1,
   ParChild=cast(CAST(c.CategoryID AS VARCHAR(200)) AS VARCHAR(MAX))
FROM   retail.Category c
WHERE c.fParentCategoryID is NULL
Run Code Online (Sandbox Code Playgroud)

如果您的数据在该 select 语句中可能混合存在 null 和非 null 值,则还可以在其周围使用 ISNULL 将任何 null 视为空字符串。

当您获得诸如“,461,464”之类的值时,它可能需要对其生成的 ParChild 值进行一些清理,因此您可能需要去掉开头的逗号。