简体   繁体   English

如何在 SQL Server 2014 中呈现分层数据

[英]How to present hierarchical data in SQL Server 2014

I have two tables Company and CompanyRelationShip .我有两个表CompanyCompanyRelationShip

DECLARE @Company TABLE (
    CompanyId INT
    ,RootCompanyId INT
    ,CompanyName VARCHAR(100)
    )

INSERT INTO @Company
VALUES (2,2,'ROOT')
,(106,2,'ABC')
,(105,2,'CDF')
,(3,3,'ROOT2')
,(150,3,'YXZ')
,(151,3,'XZX')


DECLARE @CompanyRelationShip TABLE (
    PrimaryCompanyId INT
    ,CompanyId INT
    )

INSERT INTO @CompanyRelationShip
VALUES (2,2)
,(2,106)
,(2,105)
,(106,105)
,(3,3)
,(3,151)
,(3,150)
,(151,150)

I want the result in the below format我想要以下格式的结果

CompanyId   PrimayCompanyId PrimaryCompanyName  RootCompanyId   RootCompanyName
2                 2              ROOT               2               ROOT
106               2              ROOT               2               ROOT
105              106             ABC                2               ROOT
3                 3              ROOT2              3               ROOT2
151              3               ROOT2              3               ROOT2
150              151             XZX                3               ROOT2

I have tried the below query to get the result我已经尝试了以下查询来获得结果

WITH PrimayCompany
AS (
    SELECT CR.PrimaryCompanyId
        ,C.CompanyName
    FROM @CompanyRelationShip CR
    JOIN @Company C ON CR.CompanyId = CR.PrimaryCompanyId
    )
    ,RootCompany
AS (
    SELECT RootCompanyId
        ,CompanyName
    FROM @Company
    WHERE CompanyId = RootCompanyId
    )
SELECT C.CompanyId
    ,C.RootCompanyId
    ,RC.CompanyName
    ,CR.PrimaryCompanyId
    ,PC.CompanyName
FROM @Company C
LEFT JOIN @CompanyRelationShip CR ON C.CompanyId = CR.PrimaryCompanyId
LEFT JOIN PrimayCompany PC ON PC.PrimaryCompanyId = CR.PrimaryCompanyId
LEFT JOIN RootCompany RC ON RC.RootCompanyId = CR.PrimaryCompanyId

I would really appreciate a bit of help.我真的很感激一点帮助。

In my comment I asked you, why you would need the table @CompanyRelationShip at all... This is just adding a hell of a lot of complexity and potentials for errors.在我的评论中,我问你,为什么你需要@CompanyRelationShip表......这只是增加了大量的复杂性和出错的可能性。

My suggestion relies on the first table alone.我的建议仅依赖于第一张桌子。 Look, how I've changed the parent IDs of 105 and 151 to place them below in the hierarchy.看,我是如何更改 105 和 151 的父 ID 以将它们放在层次结构中的下方的。 Just to show the principles I've added a second child below 150 :只是为了展示我在 150 以下添加了第二个孩子的原则:

DECLARE @Company TABLE (
    CompanyId INT
    ,RootCompanyId INT
    ,CompanyName VARCHAR(100)
    );

INSERT INTO @Company
VALUES (2,2,'ROOT')
,(106,2,'ABC')
,(105,106,'CDF')
,(3,3,'ROOT2')
,(150,3,'YXZ')
,(151,150,'XZX')
,(152,150,'Second below 150');

--the query --查询

WITH recCTE AS
(
    SELECT CompanyId AS [RootId],CompanyName AS [RootName],*,1 AS HierarchyLevel FROM @Company WHERE CompanyId=RootCompanyId
    UNION ALL
    SELECT rc.RootId,rc.RootName,c.*,rc.HierarchyLevel+1
    FROM @Company c
    INNER JOIN recCTE rc ON c.RootCompanyId=rc.CompanyId AND c.CompanyId<>rc.CompanyId
)
SELECT RootId
      ,RootName
      ,RootCompanyId AS [PrevId]
      ,CompanyId
      ,CompanyName
      ,HierarchyLevel 
FROM recCTE rc
ORDER BY RootId,HierarchyLevel;

The result结果

RootId  RootName    PrevId  CompanyId   CompanyName     HierarchyLevel
2       ROOT        2       2           ROOT                1
2       ROOT        2       106         ABC                 2
2       ROOT        106     105         CDF                 3
3       ROOT2       3       3           ROOT2               1
3       ROOT2       3       150         YXZ                 2
3       ROOT2       150     151         XZX                 3
3       ROOT2       150     152         Second below 150    3

The idea in short:简而言之这个想法:

  • We use aa recursive CTE (which is a rather iterative concept actually).我们使用递归 CTE (实际上是一个相当迭代的概念)。
  • The first SELECT (the anchor ) starts with the companies, where the two IDs match.第一个 SELECT(锚点)以两个 ID 匹配的公司开始。
  • The second SELECT after UNION ALL picks the next level by joining to the intermediate result line UNION ALL 之后的第二个 SELECT 通过连接到中间结果行来选择下一个级别
  • The two columns RootId and RootName are just passed through to show up in your final set. RootIdRootName两列刚刚通过以显示在您的最终集合中。

The HierarchyLevel is the position within the line, thus placing 105 within ROOT, but below 106. HierarchyLevel是行内的位置,因此将 105 放置ROOT,但低于106。

Hope this helps...希望这可以帮助...

A solution for the given structure给定结构的解决方案

As told, the given structure is not the best choice and should be altered.如上所述,给定的结构不是最佳选择,应该进行更改。 But if you have to stick to this, you might try something along this:但是,如果您必须坚持这一点,您可以尝试以下方法:

WITH recCTE AS
(
    SELECT CompanyId AS [RootId],CompanyName AS [RootName],*,1 AS HierarchyLevel FROM @Company WHERE CompanyId=RootCompanyId
    UNION ALL
    SELECT rc.RootId,rc.RootName,c.*,rc.HierarchyLevel+1
    FROM @Company c
    INNER JOIN recCTE rc ON c.RootCompanyId=rc.CompanyId AND c.CompanyId<>rc.CompanyId
)
SELECT rc.CompanyId
      ,rc.CompanyName  
      ,COALESCE(crs.PrimaryCompanyId,rc.RootCompanyId) AS ComputedPrevId
      ,COALESCE(c1.CompanyName,rc.RootName) AS ComputedPrevName
      ,rc.RootId
      ,rc.RootName
FROM recCTE rc
LEFT JOIN @CompanyRelationShip  crs ON rc.CompanyId=crs.CompanyId AND rc.RootCompanyId<>crs.PrimaryCompanyId
LEFT JOIN @Company c1 ON crs.PrimaryCompanyId=c1.CompanyId
ORDER BY rc.RootId,rc.HierarchyLevel;

This will first use a recursive CTE to find the children below their root companies and the will try to find the corresponding line in your relationship table.这将首先使用递归 CTE 来查找其根公司下面的子项,并尝试在您的关系表中找到相应的行。

If you use just SELECT * instead of the column list you can see the full set.如果您只使用SELECT *而不是列列表,您可以看到完整的集合。 Using LEFT JOIN will return NULL , when the ON claus is not met.当不满足ON子句时,使用LEFT JOIN将返回NULL

COALESCE will return the first non-NULL value, so - hopefully - the one you are after. COALESCE将返回第一个非 NULL 值,所以 - 希望 - 你所追求的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM