收集在 SQL 服务器中的关系 table 中捕获的树中的所有节点
Collect all the nodes in a tree captured within a relational table in SQL Server
我有一个具有以下架构的 table:
CREATE TABLE Feature
(
FeatureId INT IDENTITY(1,1),
ParentFeatureId INT,
TargetObjectType VARCHAR(64)
)
如您所见,它定义了一个特征树。我有兴趣收集在给定节点下找到的所有后代。
我目前的解决方案对我来说似乎很尴尬:
IF OBJECT_ID('tempdb..#features') IS NOT NULL
DROP TABLE #features
SELECT
0 FeatureId, TargetObjectType, ParentFeatureID
INTO
#features
FROM
Feature
WHERE
1 = 0
INSERT INTO #features
SELECT
FeatureId, TargetObjectType, ParentFeatureID
FROM
Feature
WHERE
TargetObjectType IN ('Root1', 'Root2')
WHILE @@ROWCOUNT > 0
INSERT INTO #features
SELECT FeatureId, TargetObjectType, ParentFeatureID
FROM Feature f
WHERE ParentFeatureID IN (SELECT FeatureId FROM #features)
AND NOT EXISTS (SELECT 1 FROM #features WHERE FeatureId = f.FeatureId)
SELECT * FROM #features
有没有更优雅的方法呢?也许使用递归 CTE?
数据量不大(最多几千条记录)。所有数据都代表一个只有几个层次结构的森林,最多说 7 个。
这是一个递归 CTE,它会为您提供 child 节点,无论您作为顶部参数传入的任何 FeatureId。如果您只想要 children,请将 cte 的第一个 select 语句中的 WHERE
子句更改为 WHERE e.ParentFeatureId = @lookupFeatureId
而不是 WHERE e.FeatureId = @lookupFeatureId
DECLARE @lookupFeatureId INT; SET @lookupFeatureId = 6;
WITH cte (FeatureId, ParentFeatureId, TargetObjectType, [Level])
AS
(
SELECT e.FeatureId, e.ParentFeatureId, e.TargetObjectType, 0 AS Level
FROM Feature AS e
WHERE e.FeatureId = @lookupFeatureId
UNION ALL
SELECT e.FeatureId, e.ParentFeatureId, e.TargetObjectType, d.[Level] + 1
FROM Feature AS e
INNER JOIN cte AS d
ON e.ParentFeatureId = d.FeatureId
)
SELECT FeatureId, ParentFeatureId, TargetObjectType, [Level]
FROM cte
我有一个具有以下架构的 table:
CREATE TABLE Feature
(
FeatureId INT IDENTITY(1,1),
ParentFeatureId INT,
TargetObjectType VARCHAR(64)
)
如您所见,它定义了一个特征树。我有兴趣收集在给定节点下找到的所有后代。
我目前的解决方案对我来说似乎很尴尬:
IF OBJECT_ID('tempdb..#features') IS NOT NULL
DROP TABLE #features
SELECT
0 FeatureId, TargetObjectType, ParentFeatureID
INTO
#features
FROM
Feature
WHERE
1 = 0
INSERT INTO #features
SELECT
FeatureId, TargetObjectType, ParentFeatureID
FROM
Feature
WHERE
TargetObjectType IN ('Root1', 'Root2')
WHILE @@ROWCOUNT > 0
INSERT INTO #features
SELECT FeatureId, TargetObjectType, ParentFeatureID
FROM Feature f
WHERE ParentFeatureID IN (SELECT FeatureId FROM #features)
AND NOT EXISTS (SELECT 1 FROM #features WHERE FeatureId = f.FeatureId)
SELECT * FROM #features
有没有更优雅的方法呢?也许使用递归 CTE?
数据量不大(最多几千条记录)。所有数据都代表一个只有几个层次结构的森林,最多说 7 个。
这是一个递归 CTE,它会为您提供 child 节点,无论您作为顶部参数传入的任何 FeatureId。如果您只想要 children,请将 cte 的第一个 select 语句中的 WHERE
子句更改为 WHERE e.ParentFeatureId = @lookupFeatureId
而不是 WHERE e.FeatureId = @lookupFeatureId
DECLARE @lookupFeatureId INT; SET @lookupFeatureId = 6;
WITH cte (FeatureId, ParentFeatureId, TargetObjectType, [Level])
AS
(
SELECT e.FeatureId, e.ParentFeatureId, e.TargetObjectType, 0 AS Level
FROM Feature AS e
WHERE e.FeatureId = @lookupFeatureId
UNION ALL
SELECT e.FeatureId, e.ParentFeatureId, e.TargetObjectType, d.[Level] + 1
FROM Feature AS e
INNER JOIN cte AS d
ON e.ParentFeatureId = d.FeatureId
)
SELECT FeatureId, ParentFeatureId, TargetObjectType, [Level]
FROM cte