sql-server - 如何在 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
我真的很感激一些帮助。
解决方案
在我的评论中,我问你,为什么你需要这张桌子@CompanyRelationShip
......这只是增加了很多复杂性和潜在的错误。
我的建议仅依赖于第一张桌子。看,我如何更改 105 和 151 的父 ID 以将它们放在层次结构的下方。只是为了展示我在 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');
--查询
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。
希望这可以帮助...
给定结构的解决方案
如前所述,给定的结构不是最好的选择,应该改变。但如果你必须坚持这一点,你可以尝试这样做:
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 查找其根公司下的子代,然后尝试在您的关系表中找到相应的行。
如果您只使用SELECT *
而不是列列表,您可以看到完整的集合。当不满足条款时,使用LEFT JOIN
将返回。NULL
ON
COALESCE
将返回第一个非 NULL 值,所以 - 希望 - 你之后的那个。
推荐阅读
- c# - Azure 使用 Azure 函数保护 WCF asmx
- php - 在 UsersType.php FOS USER Symfony 3 上注入 EntityType
- reactjs - 在特定组件中呈现时,React-redux 调度未定义
- ios - Flutter:flutter_downloader SQL 无法正常工作
- android - 如何在 Android 上做一个简单的 Flutter 秒表前台服务?
- powershell - 禁用打印后台处理程序脚本
- legend - 单击图表时,在 Altair 交互式图例中保留多选
- python - Python - 如果名称包含在任何行中,则保留组的所有行
- python - 如何使用 Python 从 java 文件中提取类变量和类方法?
- javascript - 在javascript中使用百里香对象填充输入选择html时获取未定义