扁平化层次结构
Flatten hierarchy
我有以下 table:
create table T (
idGeo INT IDENTITY(1,1),
GEO VARCHAR(64),
PARENTID INT
);
insert into T (GEO, PARENTID) values
( 'EMEA', NULL),
( 'France', 1),
( 'mIDCAPSfRANCE', 2),
( 'Germany', 1),
( 'France exl midcaps', 2),
( 'Amercias', NULL),
( 'US', 6);
预期结果
我想在单独的列中获取层次结构。
这是我试过的 https://sqlize.online/sql/mssql2017/7f34918507bae9d9b74af96c5f5e83dc/
select T.idGeo, T.GEO, T1.GEO [GEO Level 1], T2.GEO [GEO Level 2]
from T
left join T T1 on T.PARENTID = T1.idGeo
left join T T2 on T1.PARENTID = T2.idGeo;
问题是例如第 1 行,我想获得 geo level1 EMEA,但我得到的是空值。我该如何更正它?
你可以使用 CHOOSE
到 return 你想要的值,基于“级别”,这是通过 COUNT
非 [=13= 的数量获得的] GEO
的值:
SELECT T.idGeo,
T.GEO,
CHOOSE(C.Level,T.GEO,T1.GEO,T2.GEO) AS [GEO Level 1],
CHOOSE(C.Level-1,T.GEO,T1.GEO,T2.GEO) AS [GEO Level 1],
CHOOSE(C.Level-2,T.GEO,T1.GEO,T2.GEO) AS [GEO Level 2]
FROM dbo.T
LEFT JOIN dbo.T T1 ON T.PARENTID = T1.idGeo
LEFT JOIN dbo.T T2 ON T1.PARENTID = T2.idGeo
CROSS APPLY ((SELECT COUNT(V.GEO) AS Level
FROM (VALUES(T.GEO),(T1.GEO),(T2.GEO))V(GEO))) C;
您可以尝试使用 CTE 递归 Flatten 层次结构的另一种方法,CTE 递归 self-join 获取所有 GEO
层次结构,这可能对您有所帮助
如果您的层次结构级别超过 2,则减少太多 OUTER JOIN
。
我们可以通过添加新的条件聚合函数轻松创建新关卡。
;WITH CTE AS (
SELECT idGeo,GEO cGEO,GEO,PARENTID,0 level
FROM T
UNION ALL
SELECT t.idGeo,t.GEO,c.GEO,c.PARENTID,level+1
FROM CTE c
INNER JOIN T t
ON t.PARENTID = c.idGeo
)
SELECT idGeo,
cGEO,
MAX(CASE WHEN rn = 1 THEN GEO END) [GEO Level 1],
MAX(CASE WHEN rn = 2 THEN GEO END) [GEO Level 2],
MAX(CASE WHEN rn = 3 THEN GEO END) [GEO Level 3]
FROM (
SELECT *,ROW_NUMBER() OVER(PARTITION BY idGeo ORDER BY level desc) rn
FROM CTE
)t1
GROUP BY idGeo,
cGEO
ORDER BY idGeo
我有以下 table:
create table T (
idGeo INT IDENTITY(1,1),
GEO VARCHAR(64),
PARENTID INT
);
insert into T (GEO, PARENTID) values
( 'EMEA', NULL),
( 'France', 1),
( 'mIDCAPSfRANCE', 2),
( 'Germany', 1),
( 'France exl midcaps', 2),
( 'Amercias', NULL),
( 'US', 6);
预期结果
我想在单独的列中获取层次结构。
这是我试过的 https://sqlize.online/sql/mssql2017/7f34918507bae9d9b74af96c5f5e83dc/
select T.idGeo, T.GEO, T1.GEO [GEO Level 1], T2.GEO [GEO Level 2]
from T
left join T T1 on T.PARENTID = T1.idGeo
left join T T2 on T1.PARENTID = T2.idGeo;
问题是例如第 1 行,我想获得 geo level1 EMEA,但我得到的是空值。我该如何更正它?
你可以使用 CHOOSE
到 return 你想要的值,基于“级别”,这是通过 COUNT
非 [=13= 的数量获得的] GEO
的值:
SELECT T.idGeo,
T.GEO,
CHOOSE(C.Level,T.GEO,T1.GEO,T2.GEO) AS [GEO Level 1],
CHOOSE(C.Level-1,T.GEO,T1.GEO,T2.GEO) AS [GEO Level 1],
CHOOSE(C.Level-2,T.GEO,T1.GEO,T2.GEO) AS [GEO Level 2]
FROM dbo.T
LEFT JOIN dbo.T T1 ON T.PARENTID = T1.idGeo
LEFT JOIN dbo.T T2 ON T1.PARENTID = T2.idGeo
CROSS APPLY ((SELECT COUNT(V.GEO) AS Level
FROM (VALUES(T.GEO),(T1.GEO),(T2.GEO))V(GEO))) C;
您可以尝试使用 CTE 递归 Flatten 层次结构的另一种方法,CTE 递归 self-join 获取所有 GEO
层次结构,这可能对您有所帮助
如果您的层次结构级别超过 2,则减少太多 OUTER JOIN
。
我们可以通过添加新的条件聚合函数轻松创建新关卡。
;WITH CTE AS (
SELECT idGeo,GEO cGEO,GEO,PARENTID,0 level
FROM T
UNION ALL
SELECT t.idGeo,t.GEO,c.GEO,c.PARENTID,level+1
FROM CTE c
INNER JOIN T t
ON t.PARENTID = c.idGeo
)
SELECT idGeo,
cGEO,
MAX(CASE WHEN rn = 1 THEN GEO END) [GEO Level 1],
MAX(CASE WHEN rn = 2 THEN GEO END) [GEO Level 2],
MAX(CASE WHEN rn = 3 THEN GEO END) [GEO Level 3]
FROM (
SELECT *,ROW_NUMBER() OVER(PARTITION BY idGeo ORDER BY level desc) rn
FROM CTE
)t1
GROUP BY idGeo,
cGEO
ORDER BY idGeo