Parent Id 不在列表中时递归 CTE
Recursive CTE while Parent Id not in a List
我有以下嵌套集
结果就是这棵树
1 -
|---- 2 -
| |---- 4 -
| |---- 7
| |---- 8
|----10 -
|---- 9
3 -
|---- 5
|---- 6
13-
|---- 11
|---- 12
我有一份产品清单
SELECT 身份证、姓名...
来自产品
与类别的 many-to-many 关系。所有类别都可以有促销。好的,问题来了。
假设我在类别 7、8、6 中有一个 ProductX。以及类别 1、2、3 中的促销。我需要获得最接近的 parent 每个类别的促销,或者直到没有更多 parent 为止。
最终结果应该是
CategoryId PromotionPrice
2 price...
3 price...
我有什么
WITH Promotions (CategoryId, PromotionPrice)
{
SELECT CategoryId, PromotionPrice
FROM Promotions
}
SELECT CategoryId, PromotionPrice
FROM NestedSet s1
LEFT JOIN NestedSet s2 ON s1.ParentId = s2.Id
LEFT JOIN Promotions p ON s1.CategoryId = p.CategoryId
然后获取 Better Promotion(我知道该怎么做)并应用于主查询 SELECT * FROM Products;对于每个产品(所以只是一个简单的连接)。
我的问题是我知道我需要使用(或者我认为我需要使用)递归 CTE,但我不知道该怎么做。因为它应该只对每一行递归,并且只在它找到该行的促销之前。
编辑(我将尝试解释其中的逻辑)。
ProductId CategoryId
1 7
1 8
1 6
该产品有 2 个直接 parent:4 个(来自 7 和 8)和 3 个(来自 6)
我在 CategoryIds 中有促销活动:1、2、3。
第一轮查询结果
CategoryId ParentId PromotionPrice
7 4 NULL
8 4 NULL
6 3 10
重要的是 ParentId,所以我可以 GroupBy ParentId,结果将是
CategoryId PromotionPrice
4 NULL
3 10
好的,因为 promotionPrice 是 NULL 我需要去他的 parent(在本例中是 2)所以上面的查询需要 return
CategoryId ParentId PromotionPrice
4 2 NULL
3 NULL 10
由于 PromotionPrice 为 Null,我必须检查是否有针对 Category2 的促销,因此结果为
CategoryId ParentId PromotionPrice
2 1 15
3 NULL 10
到此为止。如果我从 Category2 中删除促销活动,它应该再进行一轮:
CategoryId ParentId PromotionPrice
1 NULL 5
3 NULL 10
在这一点上,因为没有更多的 parents,PromotionPrice 是否为 null 并不重要。问题是我需要一直努力寻找升职机会。
因为我正在查看 SortPath 已经拥有所有信息,只需要将其分解并递归地向后查找直到找到具有促销的 ID,我仍然对如何实现这一点一无所知。
希望这对解释有所帮助。
注意:我稍作编辑以反映您提供的样本数据。
设置
这是我必须代表您的嵌套集的内容:
declare @nestedSet table (
id int,
parentId int
);
insert @nestedSet values
(1, null), (2, 1), (4, 2), (7, 4), (8, 4), (10, 1), (9, 10), (1004, 1),
(3, null), (5, 3), (6, 3),
(13, null), (11, 13), (12, 13);
这是我为您的促销活动制作的:
declare @promotions table (
promotionId int identity(1,1),
categoryId int,
price float
);
insert @promotions values (1, 5), (2, 15), (3, 10);
还有您的产品,我已将其重命名为 productCategories 以更好地反映其内容:
declare @productCategories table (productId int, categoryId int);
insert @productCategories values (1,7),(1,8),(1,6);
解决方案
作为主播,刚刚拉进了产品table。但我认为在您的用例中,您需要一个过滤器来挑选出合适的基础产品。然后我做了一个计算来检查该类别是否已经是促销活动。如果是,那么它代表一个叶节点。
在递归中,我只是为每个不是叶子的节点向上移动了嵌套集的层次结构。我又做了一次计算,看分类是不是推广,看是不是叶节点。
从结果中,我选择了所有的叶子节点,按价格排序,输出最前面的那个。
declare @productId int = 1;
with
traverse as (
select categoryId,
parentId,
isLeaf = iif(exists (
select 0
from @promotions pm
where pd.categoryId = pm.categoryId
), 1, 0)
from @productCategories pd
join @nestedSet n on pd.categoryId = n.id
where pd.productId = @productId
union all
select categoryId = par.id,
par.parentId,
isLeaf = iif(exists (
select 0
from @promotions pm
where par.id = pm.categoryId
), 1, 0)
from traverse pd
join @nestedSet par on pd.parentId = par.id
where pd.isLeaf = 0
)
select
top 1 p.*
from traverse t
join @promotions p on t.categoryId = p.categoryId
where isLeaf = 1
order by p.price
我有以下嵌套集
结果就是这棵树
1 -
|---- 2 -
| |---- 4 -
| |---- 7
| |---- 8
|----10 -
|---- 9
3 -
|---- 5
|---- 6
13-
|---- 11
|---- 12
我有一份产品清单 SELECT 身份证、姓名... 来自产品
与类别的 many-to-many 关系。所有类别都可以有促销。好的,问题来了。
假设我在类别 7、8、6 中有一个 ProductX。以及类别 1、2、3 中的促销。我需要获得最接近的 parent 每个类别的促销,或者直到没有更多 parent 为止。
最终结果应该是
CategoryId PromotionPrice
2 price...
3 price...
我有什么
WITH Promotions (CategoryId, PromotionPrice)
{
SELECT CategoryId, PromotionPrice
FROM Promotions
}
SELECT CategoryId, PromotionPrice
FROM NestedSet s1
LEFT JOIN NestedSet s2 ON s1.ParentId = s2.Id
LEFT JOIN Promotions p ON s1.CategoryId = p.CategoryId
然后获取 Better Promotion(我知道该怎么做)并应用于主查询 SELECT * FROM Products;对于每个产品(所以只是一个简单的连接)。
我的问题是我知道我需要使用(或者我认为我需要使用)递归 CTE,但我不知道该怎么做。因为它应该只对每一行递归,并且只在它找到该行的促销之前。
编辑(我将尝试解释其中的逻辑)。
ProductId CategoryId
1 7
1 8
1 6
该产品有 2 个直接 parent:4 个(来自 7 和 8)和 3 个(来自 6) 我在 CategoryIds 中有促销活动:1、2、3。 第一轮查询结果
CategoryId ParentId PromotionPrice
7 4 NULL
8 4 NULL
6 3 10
重要的是 ParentId,所以我可以 GroupBy ParentId,结果将是
CategoryId PromotionPrice
4 NULL
3 10
好的,因为 promotionPrice 是 NULL 我需要去他的 parent(在本例中是 2)所以上面的查询需要 return
CategoryId ParentId PromotionPrice
4 2 NULL
3 NULL 10
由于 PromotionPrice 为 Null,我必须检查是否有针对 Category2 的促销,因此结果为
CategoryId ParentId PromotionPrice
2 1 15
3 NULL 10
到此为止。如果我从 Category2 中删除促销活动,它应该再进行一轮:
CategoryId ParentId PromotionPrice
1 NULL 5
3 NULL 10
在这一点上,因为没有更多的 parents,PromotionPrice 是否为 null 并不重要。问题是我需要一直努力寻找升职机会。
因为我正在查看 SortPath 已经拥有所有信息,只需要将其分解并递归地向后查找直到找到具有促销的 ID,我仍然对如何实现这一点一无所知。
希望这对解释有所帮助。
注意:我稍作编辑以反映您提供的样本数据。
设置
这是我必须代表您的嵌套集的内容:
declare @nestedSet table (
id int,
parentId int
);
insert @nestedSet values
(1, null), (2, 1), (4, 2), (7, 4), (8, 4), (10, 1), (9, 10), (1004, 1),
(3, null), (5, 3), (6, 3),
(13, null), (11, 13), (12, 13);
这是我为您的促销活动制作的:
declare @promotions table (
promotionId int identity(1,1),
categoryId int,
price float
);
insert @promotions values (1, 5), (2, 15), (3, 10);
还有您的产品,我已将其重命名为 productCategories 以更好地反映其内容:
declare @productCategories table (productId int, categoryId int);
insert @productCategories values (1,7),(1,8),(1,6);
解决方案
作为主播,刚刚拉进了产品table。但我认为在您的用例中,您需要一个过滤器来挑选出合适的基础产品。然后我做了一个计算来检查该类别是否已经是促销活动。如果是,那么它代表一个叶节点。
在递归中,我只是为每个不是叶子的节点向上移动了嵌套集的层次结构。我又做了一次计算,看分类是不是推广,看是不是叶节点。
从结果中,我选择了所有的叶子节点,按价格排序,输出最前面的那个。
declare @productId int = 1;
with
traverse as (
select categoryId,
parentId,
isLeaf = iif(exists (
select 0
from @promotions pm
where pd.categoryId = pm.categoryId
), 1, 0)
from @productCategories pd
join @nestedSet n on pd.categoryId = n.id
where pd.productId = @productId
union all
select categoryId = par.id,
par.parentId,
isLeaf = iif(exists (
select 0
from @promotions pm
where par.id = pm.categoryId
), 1, 0)
from traverse pd
join @nestedSet par on pd.parentId = par.id
where pd.isLeaf = 0
)
select
top 1 p.*
from traverse t
join @promotions p on t.categoryId = p.categoryId
where isLeaf = 1
order by p.price