MySQL通过子验证父母

MySQL validating parents by children

提问人:Tomas Novak 提问时间:2/22/2023 最后编辑:user1191247Tomas Novak 更新时间:2/24/2023 访问量:68

问:

我在 Visual Studio 中编程,但我需要在 mySQL (v8.0.28) 表上执行验证,我想如果它在服务器上作为过程执行会更快。不幸的是,我的MySQL编程技能非常有限。

这相当于我的表格:

节点 ID 节点级别 节点父级 节点值 节点有效
0 0 0
1 1 0 0
2 2 1 0
3 3 2 2023-03-03 1
4 0 0
5 1 4 0
6 2 5 0
7 3 6 2023-03-03 1
8 0 0
9 1 8 0
10 1 8 0

它的工作方式类似于 Treeview 节点,我能够通过以下行验证底层节点的状态:

UPDATE `bs`.`valitable` 
SET `NodeValid`='1' 
WHERE `NodeLevel`='3' AND `NodeValue` > '2023-02-22';

我如何遍历 ='2' 的节点,因为我需要检查是否所有子项都有效 = 1(然后父项有效 = 1),否则父项有效 = 0。NodeLevel

我发现了一些时间......DO、FOR 循环、游标,但我无法编写正确的语法来正确执行此操作。或者 - 有没有其他方法可以做到这一点?

我尝试在Visual Studio中执行此操作,但它太慢了,因为它需要加载整个表,继续并保存回来。随着表的增长,它无法使用,所以我希望mySQL过程可以加快该过程,因为它可以直接从服务器运行。

mysql 邻接列表 递归 cte

评论

2赞 Akina 2/22/2023
您需要递归 CTE - 研究 WITH 子句(公用表表达式)。
0赞 Tomas Novak 2/22/2023
这对我来说太复杂了,谢谢你的建议,我在 VS 中做到了......
1赞 Akina 2/22/2023
这很简单。提出一个好的结构化查询语言 (SQL) 问题的提示,#5 和 #3 - 我会告诉你这真的很简单。
0赞 Tomas Novak 2/22/2023
好的,@Akina,预期结果是根据所提到的子 NodeValid 状态编辑 NodeValid 列。就我而言,它比 0/1 更复杂,但它由非常简单的规则驱动,我以后可以修改。每一层的孩子都有不同的规则,所以我会单独进行每一层。我的问题是我无法浏览“SELECT”的结果。程序应该像这样工作(我很抱歉缺少mySQL syantax):NodeLevel 3由相关代码解决:UPDATE table SET NodeValid=1 WHERE NodeLevel=3 AND NodeValue > 2023-02-22;
1赞 Martin 2/22/2023
我得到了孩子们的认可。但只有当我喂它们时。

答:

0赞 user1191247 2/23/2023 #1

您应该更改表,以便使用 NodeParent 而不是 .无论如何,这是从 NodeParent 到 NodeID 的 FK 约束所必需的,您应该具备这些约束。NULLroot

这种方法使用递归 cte 来构建叶节点 () 及其所有祖先的完整列表。因此,根据您的描述,如果所有相关的叶节点都有效,我们可以将所有祖先更新为有效():NodeLevel = 3NodeValue > '2023-02-22'

WITH RECURSIVE cte (AncestorID, LeafID) AS (

    SELECT NodeParent, NodeID
    FROM valitable WHERE NodeLevel = 3

    UNION ALL

    SELECT v.NodeParent, c.LeafID
    FROM valitable v
    JOIN cte c ON v.NodeID = c.AncestorID AND v.NodeParent IS NOT NULL

)
UPDATE valitable a
JOIN (
    SELECT cte.AncestorID, MIN(l.NodeValue > '2023-02-22') valid
    FROM cte
    JOIN valitable l ON cte.LeafID = l.NodeID
    GROUP BY cte.AncestorID
) j ON a.NodeID = j.AncestorID
SET a.NodeValid = j.valid;

为此,您需要按预期工作,您需要先运行 NodeLevel 3 节点的初始更新。

这不会对与 NodeLevel 3 节点没有关系的节点进行任何更改,因为没有对这些节点的规则进行解释。


更新

要设置节点与 NodeLevel 3 节点无关的位置,您可以在 update 语句中更改 to,但您需要确保它仅在 NodeLevel < 3 的地方更新,否则它将包含所有 NodeLevel 3 节点,因为它们未作为祖先包含在 cte 中:NodeValid = NULLJOINLEFT JOINNULL

-- start with your initial update
UPDATE valitable
SET NodeValid = NodeValue > '2023-02-22' -- 1 if meets criterion, 0 if not
WHERE NodeLevel = 3;

WITH RECURSIVE cte (AncestorID, LeafID) AS (

    SELECT NodeParent, NodeID
    FROM valitable WHERE NodeLevel = 3

    UNION ALL

    SELECT v.NodeParent, c.LeafID
    FROM valitable v
    JOIN cte c ON v.NodeID = c.AncestorID AND v.NodeParent IS NOT NULL

)
UPDATE valitable a
LEFT JOIN (
    SELECT cte.AncestorID, MIN(l.NodeValue > '2023-02-22') valid
    FROM cte
    JOIN valitable l ON cte.LeafID = l.NodeID
    GROUP BY cte.AncestorID
) j ON a.NodeID = j.AncestorID
SET a.NodeValid = j.valid
WHERE a.NodeLevel < 3;

评论

0赞 Tomas Novak 2/23/2023
感谢您的回答!是否可以将所有父节点的值更改为 NULL,而不与 NodeLevel 3 相关?其中 0 以 NULL 为主?
1赞 Tomas Novak 2/23/2023
完美,感谢您的帮助。当我有可能的时候,我会投赞成票。