如何在 SQL Server 2014 中呈现分层数据
How to present hierarchical data in SQL Server 2014
我有两个表 Company
和 CompanyRelationShip
。
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)
我想要以下格式的结果
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
我尝试了以下查询来获得结果
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
非常感谢您的帮助。
在我的评论中,我问过你,为什么你需要 table @CompanyRelationShip
...这只会增加大量的复杂性和潜在的错误。
我的建议仅依赖第一个 table。看,我是如何更改 105 和 151 的 parent ID 以将它们放置在层次结构中的下方。只是为了说明我在 150:
下面添加了第二个 child 的原则
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');
--查询
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;
结果
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
简而言之:
- 我们使用 递归 CTE(实际上是 迭代 概念)。
- 第一个 SELECT(锚点)以公司开头,两个 ID 匹配。
- UNION ALL后的第二个SELECT通过加入到中间结果行
选取下一级
RootId
和 RootName
两列刚刚通过并显示在您的最终集中。
HierarchyLevel
是行内的位置,因此105在ROOT内,但是在106.[=下面23=]
希望这对您有所帮助...
给定结构的解决方案
如前所述,给定的结构不是最佳选择,应该进行更改。但如果你必须坚持这一点,你可以试试这个:
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;
这将首先使用递归 CTE 找到其根公司下面的 children,然后将尝试在您的关系 table.
中找到相应的行
如果您只使用 SELECT *
而不是列列表,您可以看到完整的集合。
当不满足 ON
子句时,使用 LEFT JOIN
将 return NULL
。
COALESCE
将 return 第一个 non-NULL 值,因此 - 希望 - 您所追求的值。
我有两个表 Company
和 CompanyRelationShip
。
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)
我想要以下格式的结果
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
我尝试了以下查询来获得结果
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
非常感谢您的帮助。
在我的评论中,我问过你,为什么你需要 table @CompanyRelationShip
...这只会增加大量的复杂性和潜在的错误。
我的建议仅依赖第一个 table。看,我是如何更改 105 和 151 的 parent ID 以将它们放置在层次结构中的下方。只是为了说明我在 150:
下面添加了第二个 child 的原则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');
--查询
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;
结果
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
简而言之:
- 我们使用 递归 CTE(实际上是 迭代 概念)。
- 第一个 SELECT(锚点)以公司开头,两个 ID 匹配。
- UNION ALL后的第二个SELECT通过加入到中间结果行 选取下一级
RootId
和RootName
两列刚刚通过并显示在您的最终集中。
HierarchyLevel
是行内的位置,因此105在ROOT内,但是在106.[=下面23=]
希望这对您有所帮助...
给定结构的解决方案
如前所述,给定的结构不是最佳选择,应该进行更改。但如果你必须坚持这一点,你可以试试这个:
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;
这将首先使用递归 CTE 找到其根公司下面的 children,然后将尝试在您的关系 table.
中找到相应的行如果您只使用 SELECT *
而不是列列表,您可以看到完整的集合。
当不满足 ON
子句时,使用 LEFT JOIN
将 return NULL
。
COALESCE
将 return 第一个 non-NULL 值,因此 - 希望 - 您所追求的值。