CTE会在下一次递归中使用作为CTE一部分更新的数据吗?我试图尝试这个CTE,因为WHILE循环内部类似UPDATE逻辑的性能表现不佳,我希望使用CTE可以更好地设置并且性能更好。
我在使用递归CTE更新表时遇到问题,直到父行都被正确标记为止。
SQL小提琴显示表格和基本CTE。在添加任何AND / OR或级别逻辑之前,我似乎无法让CTE爬上层次结构并将父母标记为"遇到"。
以下是示例表:
| LogicID | ParentLogic | Depth | Type | Description | Met | |--------- |------------- |------- |------ |------------------------------------- |----- | | 1 | NULL | NULL | NULL | Conditions All Met | 0 | | 2 | 1 | 1 | AND | The sky or ocean is blue | 0 | | 3 | 2 | 2 | OR | The sky is blue | 0 | | 4 | 2 | 2 | OR | The ocean is blue | 1 | | 5 | 1 | 1 | AND | The grass is green or road is black | 0 | | 6 | 5 | 2 | OR | The grass is green | 1 | | 7 | 5 | 2 | OR | The road is black | 0 | | 8 | 1 | 1 | AND | Birds, bugs or the 4 below | 0 | | 9 | 8 | 2 | OR | There are birds | 0 | | 10 | 8 | 2 | OR | There are bugs | 0 | | 11 | 8 | 2 | OR | All 4 below | 0 | | 12 | 11 | 3 | AND | There are dogs | 1 | | 13 | 11 | 3 | AND | There are cats | 1 | | 14 | 11 | 3 | AND | There are people | 1 | | 15 | 11 | 3 | AND | There are chairs | 1 |
DROP TABLE MyLogic CREATE TABLE MyLogic ( LogicID int ,ParentLogic int ,Depth int ,Type varchar(4) ,Description varchar(35) ,Met int ); INSERT INTO MyLogic ( LogicID, ParentLogic, Depth, Type, Description, Met ) VALUES ( 1, NULL, NULL, NULL, 'Conditions All Met', 0 ), ( 2, 1, 1, 'AND', 'The sky or ocean is blue', 0 ), ( 3, 2, 2, 'OR', 'The sky is blue', 0 ), ( 4, 2, 2, 'OR', 'The ocean is blue', 1 ), ( 5, 1, 1, 'AND', 'The grass is green or road is black', 0 ), ( 6, 5, 2, 'OR', 'The grass is green', 1 ), ( 7, 5, 2, 'OR', 'The road is black', 0 ), ( 8, 1, 1, 'AND', 'Birds, bugs or the 4 below', 0 ), ( 9, 8, 2, 'OR', 'There are birds', 0 ), ( 10, 8, 2, 'OR', 'There are bugs', 0 ), ( 11, 8, 2, 'OR', 'All 4 below', 0 ), ( 12, 11, 3, 'AND', 'There are dogs', 1 ), ( 13, 11, 3, 'AND', 'There are cats', 1 ), ( 14, 11, 3, 'AND', 'There are people', 1 ), ( 15, 11, 3, 'AND', 'There are chairs', 1 )
这只是一组更复杂的逻辑示例。基本上我的想法是我需要每一组孩子来“累积”#34;使用表中的逻辑到父级。深度可变,但很可能是7深。
因此,逻辑ID 12,13,14,15被AND在一起,然后将11标记为Met。然后评估9,10,11,如果有的话(OR)则将8标记为Met。依此类推,直到最高级别的父级逻辑ID 1要么遇到要么不符合。
这可以通过CTE来完成,如果是这样,有人可以帮助我实现吗?
EDIT :: 感谢您的帮助 - 这里要求的是更新声明。
DECLARE @maxdepth AS int = ( SELECT MAX (Depth) FROM MyLogic)
DECLARE @counter AS int = 0
WHILE ( @counter < @maxdepth )
BEGIN
UPDATE
UP
SET
UP.Met =
--SELECT *,
CASE
WHEN ORIG.Type = 'AND' AND ORIG.Met = 0 AND COUNTS.CountMet = 2 THEN 0
WHEN ORIG.Type = 'AND' AND ORIG.Met = 0 AND COUNTS.CountMet = 1 THEN 0
WHEN ORIG.Type = 'AND' AND ORIG.Met = 1 AND COUNTS.CountMet = 2 THEN 0
WHEN ORIG.Type = 'AND' AND ORIG.Met = 1 AND COUNTS.CountMet = 1 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 1 AND COUNTS.CountMet = 1 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 0 AND COUNTS.CountMet = 2 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 1 AND COUNTS.CountMet = 2 THEN 1
WHEN ORIG.Type = 'OR' AND ORIG.Met = 0 AND COUNTS.CountMet = 1 THEN 0
END
FROM
MyLogic UP
INNER JOIN dbo.MyLogic ORIG
ON UP.LogicID = ORIG.ParentLogic
INNER JOIN ( SELECT
DIST.ParentLogic
,COUNT(DISTINCT DIST.Met) AS CountMet
FROM
MyLogic DIST
GROUP BY
DIST.ParentLogic
) COUNTS
ON ORIG.ParentLogic = COUNTS.ParentLogic
SET @counter = @counter + 1
END
答案 0 :(得分:0)
我不相信你能用CTE在这个场景中完成你的目标。我尝试使用CTE的每种方法都取决于能否在CTE的递归部分使用GROUP BY
,这是不允许的。
这是一个可以加快更新速度的替代方案。它仍然有点迭代,但在我的快速测试中看起来好一点,主要是因为更多基于集合的方法和更少的连接需要。它应该比当前流程更有效地扩展。
DECLARE @D AS INT = ( SELECT MAX (Depth) FROM MyLogic)
WHILE @D > 0 BEGIN
UPDATE P SET
Met = C.Met
FROM MyLogic P
INNER JOIN (
SELECT
ParentLogic,
CASE
WHEN SUM(CASE WHEN Type = 'OR' THEN Met ELSE 0 END) > 0
OR SUM(CASE WHEN Type = 'AND' THEN Met ELSE 0 END) = COUNT(*)
THEN 1 ELSE 0 END AS Met
FROM MyLogic
WHERE Depth = @D
GROUP BY
ParentLogic
) C -- Only update parents with children
ON P.LogicID = C.ParentLogic
WHERE COALESCE(P.Depth, 0) = @D - 1 -- Get next level up
SET @D = @D - 1
END
SELECT * FROM MyLogic