Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 以逗号分隔的字符串显示所有父项,直到最顶端_Sql_Sql Server - Fatal编程技术网

Sql 以逗号分隔的字符串显示所有父项,直到最顶端

Sql 以逗号分隔的字符串显示所有父项,直到最顶端,sql,sql-server,Sql,Sql Server,我有一个SQL server表,我们使用SQL server 2017,Org_Relationship,它只有两列OrgId和ParentOrgId。ParentOrgId列保存任何给定组织的父组织id值,只要该值可用。我需要以逗号分隔的连接字符串显示所有组织的层次结构,从直接父级开始,一直到最终父级 有许多关于堆栈溢出的类似文章讨论了类似的主题,但我无法找到符合我需要的解决方案。我可能忽略了已经为类似问题提供的解决方案,因为我是SQL Server新手 下面给出了创建脚本和一些示例数据: C

我有一个SQL server表,我们使用SQL server 2017,Org_Relationship,它只有两列OrgId和ParentOrgId。ParentOrgId列保存任何给定组织的父组织id值,只要该值可用。我需要以逗号分隔的连接字符串显示所有组织的层次结构,从直接父级开始,一直到最终父级

有许多关于堆栈溢出的类似文章讨论了类似的主题,但我无法找到符合我需要的解决方案。我可能忽略了已经为类似问题提供的解决方案,因为我是SQL Server新手

下面给出了创建脚本和一些示例数据:

CREATE TABLE [dbo].[OrgHiearchy](
    [OrgId] [nvarchar](50) NOT NULL,
    [ParentOrgID] [nvarchar](50) NULL
)
组织ID 100和200的预期输出为:

非常感谢您的帮助。

有一个解决方案可以满足您的需要。我鼓起勇气将其应用于MS SQL Server

输出:

si_id   si_item_fullname
1   Paper
5   Paper->Non-Recycled
6   Paper->Non-Recycled->20 lb
7   Paper->Non-Recycled->40 lb
8   Paper->Non-Recycled->Scraps
2   Paper->Recycled
3   Paper->Recycled->20 lb
4   Paper->Recycled->40 lb

首先,我们将构建层次结构。为此,我们将创建一个名为Hierarchys的递归CTE

CTE的锚定部分将选择层次结构的起点。我们可以在CTE中创建包含此锚查询的基本查询,如下所示:

WITH
    [Hierarchies] ([BaseId], [Level], [Id]) AS
    (
        SELECT [OrgId], 1, [ParentOrgId]
        FROM [OrgHierarchy]
    )
SELECT *
FROM [Hierarchies]
ORDER BY [BaseId], [Level];
WITH
    [Hierarchies] ([BaseId], [Level], [Id]) AS
    (
        SELECT [OrgId], 1, [ParentOrgId]
        FROM [OrgHierarchy]
      UNION ALL
        SELECT [BaseId], [Level] + 1, [ParentOrgId]
        FROM [OrgHierarchy] INNER JOIN [Hierarchies] ON [Id] = [OrgId]
    )
SELECT *
FROM [Hierarchies]
ORDER BY [BaseId], [Level];
它提供以下输出:

BaseId      Level      Id
100         1          600011944
200         1          1045
1045        1          250013
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id
100         1          600011944
100         2          600011945
200         1          1045
200         2          250013
200         3          600021987
1045        1          250013
1045        2          600021987
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id          Hierarchy
100         1          600011944   600011944
100         2          600011945   600011944, 600011945
200         1          1045        1045
200         2          250013      1045, 250013
200         3          600021987   1045, 250013, 600021987
1045        1          250013      250013
1045        2          600021987   250013, 600021987
250013      1          600021987   600021987
600011944   1          600011945   600011945
OrgId      ParentOrgId      Hierarchy
100        600011944        600011944, 600011945
200        1045             1045, 250013, 600021987
1045       250013           250013, 600021987
250013     600021987        600021987
600011944  600011945        600011945
BaseId字段将始终包含起点的Id。对于层次结构中的每个新级别,该BaseId字段都将被复制。 当然,每个步骤的级别字段都会增加。 Id字段将包含该特定级别的父Id

因此,我们可以通过添加递归查询来扩展CTE,该查询使用UNION ALL运算符与锚查询分离,如下所示:

WITH
    [Hierarchies] ([BaseId], [Level], [Id]) AS
    (
        SELECT [OrgId], 1, [ParentOrgId]
        FROM [OrgHierarchy]
    )
SELECT *
FROM [Hierarchies]
ORDER BY [BaseId], [Level];
WITH
    [Hierarchies] ([BaseId], [Level], [Id]) AS
    (
        SELECT [OrgId], 1, [ParentOrgId]
        FROM [OrgHierarchy]
      UNION ALL
        SELECT [BaseId], [Level] + 1, [ParentOrgId]
        FROM [OrgHierarchy] INNER JOIN [Hierarchies] ON [Id] = [OrgId]
    )
SELECT *
FROM [Hierarchies]
ORDER BY [BaseId], [Level];
它提供以下输出:

BaseId      Level      Id
100         1          600011944
200         1          1045
1045        1          250013
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id
100         1          600011944
100         2          600011945
200         1          1045
200         2          250013
200         3          600021987
1045        1          250013
1045        2          600021987
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id          Hierarchy
100         1          600011944   600011944
100         2          600011945   600011944, 600011945
200         1          1045        1045
200         2          250013      1045, 250013
200         3          600021987   1045, 250013, 600021987
1045        1          250013      250013
1045        2          600021987   250013, 600021987
250013      1          600021987   600021987
600011944   1          600011945   600011945
OrgId      ParentOrgId      Hierarchy
100        600011944        600011944, 600011945
200        1045             1045, 250013, 600021987
1045       250013           250013, 600021987
250013     600021987        600021987
600011944  600011945        600011945
这一数据结构良好。 现在,我们将更新CTE下面的主查询,以将父ID分组为逗号分隔的值。 为此,我们可以使用FOR-XML查询,但是因为我们已经递归地遍历了层次结构,所以我们还可以在CTE中构建csv

让我们在CTE中包含一个名为Hierarchy的附加字段,它是一个长varchar类型,可以保存所有以逗号分隔的父ID。 锚查询只会将第一个父id放入其中。递归查询将添加逗号和新的父id

WITH
    [Hierarchies] ([BaseId], [Level], [Id], [Hierarchy]) AS
    (
        SELECT [OrgId], 1, [ParentOrgId], CAST([ParentOrgId] AS VARCHAR(MAX))
        FROM [OrgHierarchy]
      UNION ALL
        SELECT [BaseId], [Level] + 1, [ParentOrgId], [Hierarchy] + ', ' + CAST([ParentOrgId] AS VARCHAR(MAX))
        FROM [OrgHierarchy] INNER JOIN [Hierarchies] ON [Id] = [OrgId]
    )
SELECT *
FROM [Hierarchies]
ORDER BY [BaseId], [Level];
它提供以下输出:

BaseId      Level      Id
100         1          600011944
200         1          1045
1045        1          250013
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id
100         1          600011944
100         2          600011945
200         1          1045
200         2          250013
200         3          600021987
1045        1          250013
1045        2          600021987
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id          Hierarchy
100         1          600011944   600011944
100         2          600011945   600011944, 600011945
200         1          1045        1045
200         2          250013      1045, 250013
200         3          600021987   1045, 250013, 600021987
1045        1          250013      250013
1045        2          600021987   250013, 600021987
250013      1          600021987   600021987
600011944   1          600011945   600011945
OrgId      ParentOrgId      Hierarchy
100        600011944        600011944, 600011945
200        1045             1045, 250013, 600021987
1045       250013           250013, 600021987
250013     600021987        600021987
600011944  600011945        600011945
看来我们快到了。我们只需要选择所有最终记录。 为此,我们在主查询中使用交叉应用程序,将OrgHierarchy表中的原始字段与最后一个对应的CTE记录组合在一起

WITH
    [Hierarchies] ([BaseId], [Level], [Id], [Hierarchy]) AS
    (
        SELECT [OrgId], 1, [ParentOrgId], CAST([ParentOrgId] AS VARCHAR(MAX))
        FROM [OrgHierarchy]
      UNION ALL
        SELECT [BaseId], [Level] + 1, [ParentOrgId], [Hierarchy] + ', ' + CAST([ParentOrgId] AS VARCHAR(MAX))
        FROM [OrgHierarchy] INNER JOIN [Hierarchies] ON [Id] = [OrgId]
    )
SELECT [OrgId], [ParentOrgId], [Hierarchy]
FROM
    [OrgHierarchy]
    CROSS APPLY (SELECT TOP (1) [Hierarchy]
                 FROM [Hierarchies]
                 WHERE [BaseId] = [OrgId]
                 ORDER BY [Level] DESC) AS H
它提供以下输出:

BaseId      Level      Id
100         1          600011944
200         1          1045
1045        1          250013
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id
100         1          600011944
100         2          600011945
200         1          1045
200         2          250013
200         3          600021987
1045        1          250013
1045        2          600021987
250013      1          600021987
600011944   1          600011945
BaseId      Level      Id          Hierarchy
100         1          600011944   600011944
100         2          600011945   600011944, 600011945
200         1          1045        1045
200         2          250013      1045, 250013
200         3          600021987   1045, 250013, 600021987
1045        1          250013      250013
1045        2          600021987   250013, 600021987
250013      1          600021987   600021987
600011944   1          600011945   600011945
OrgId      ParentOrgId      Hierarchy
100        600011944        600011944, 600011945
200        1045             1045, 250013, 600021987
1045       250013           250013, 600021987
250013     600021987        600021987
600011944  600011945        600011945

看来我们现在结束了

递归CTE可能很棘手,但这正是您想要的:

with cte as (
      select oh.OrgId, oh.ParentOrgId,
             convert(varchar(max), oh.ParentOrgId) as parents,
             oh.ParentOrgId as working, 1 as lev
      from OrgHierarchy oh
      where not exists (select 1 from OrgHierarchy oh2 where oh2.ParentOrgId = oh.OrgId)
      union all
      select cte.OrgId, cte.ParentOrgId,
             concat(parents, ',', convert(varchar(max), oh.ParentOrgId)),
             oh.ParentOrgId, lev + 1
      from cte join
           OrgHierarchy oh
           on oh.OrgId = cte.working
      where lev < 5
      )
select top (1) with ties orgid, parentorgid, parents
from cte
order by row_number() over (partition by orgid order by lev desc);

是一把小提琴。

嗨,欢迎来到SO。要解决这个问题,您需要一个递归cte来获取所有数据。然后,您需要使用FOR XML生成带分隔符的列表。我得走了,但几个小时后我会回来看看你是不是找到了答案,还是有人给你发了答案。谢谢你的回复肖恩。我确实遇到过使用STUFF和FOR XML on stack overflow的CTE解决方案,但由于我是SQL server新手,所以无法自己实现。我会尽力去做的,不要一步到位。这些都是高级主题。首先让cte工作以获取数据。然后创建分隔字符串。嗨,肖恩。是的,我一次尝试了所有的概念,可能这就是错误。谢谢你给我指出了正确的方向。非常感谢你的回答。当我执行查询时,我得到了下面的错误。CONCAT不是一个可识别的内置函数名。它可能与我假设的组织中安装的SQL server版本有关。但再次感谢你@罗希特。你可以用+操作符替换concat。哇!非常感谢您对解决方案查询的彻底分解。我敢肯定,关于最终查询中使用的所有结构,还有很多需要了解的内容,而您所解释的方式确实让我想了解它们。谢谢你!我所要做的就是按原样运行查询,它给了我预期的输出。非常感谢!嘿,巴特,一个简短的问题。如果我们要在上面的输出中也显示OrgId,您能告诉我在上面的查询中需要修改什么吗。在层次结构列中,上述情况下OrgID 100的预期输出为100600011944、600011945。如有任何建议,将不胜感激。谢谢。我成功地使用了这种语法-Orgid+','+[Hierarchy]。非常感谢您为基于Postgre的SQL server编写了一个查询。虽然我已经标记了一个不同的解决方案作为这个特定问题的答案,但我相信我将能够利用您的建议来解决类似的问题。再次感谢您!