MySQL - 当代码片段中存在时会抛出错误

标签 mysql sql

我正在阅读此页面 https://www.sqlteam.com/articles/more-trees-hierarchies-in-sql (关于在 SQL 中管理分层数据的好文章)并在 MySQL 中进行操作,并尝试运行此 SQL 片段。

WHILE EXISTS (SELECT * FROM Tree WHERE Depth Is Null) 
UPDATE T SET T.depth = P.Depth + 1, 
T.Lineage = P.Lineage + Ltrim(Str(T.ParentNode,6,0)) + '/' 
FROM Tree AS T 
INNER JOIN Tree AS P ON (T.ParentNode=P.Node) 
WHERE P.Depth>=0 
AND P.Lineage Is Not Null 
AND T.Depth Is Null

除非我收到以下错误:

You have an error in your SQL syntax; it seems the error is around: 'WHILE EXISTS ( SELECT * FROM Tree WHERE Depth Is Null ) UPDATE' at line 1

我尝试根据 While exists in mysql 中的建议添加 BEGINENDEND WHILE 等。但仍然无法正常工作。

您可以尝试在 SQL 验证器中运行上面的代码片段(https://www.eversql.com/sql-syntax-check-validator/ 是一个很好的免费在线验证器)并查看错误。

我正在寻找有关为什么上述代码片段在博客中不起作用的建议/可以更改哪些内容以实现相同的结果。

更新 - 添加更多数据

感谢@danblack 建议添加更多数据以使其成为可验证的示例。

我当前的表格

Node    ParentNode  EmployeeID  Depth   Lineage
100     NULL        1001        0       /
101     100         1002        NULL    NULL
102     101         1003        NULL    NULL
103     102         1004        NULL    NULL
104     102         1005        NULL    NULL
105     102         1006        NULL    NULL

代码段运行后应该是什么样子

Node    ParentNode  EmployeeID  Depth   Lineage
100     NULL        1001        0       /
101     100         1002        1       /100/
102     101         1003        2       /100/101/
103     102         1004        3       /100/101/102/
104     102         1005        3       /100/101/102/
105     102         1006        3       /100/101/102/

@danblack 指出该代码片段是 Microsoft SQL,而不是 MySQL,应该使用递归 CTE 来执行此操作。这是我的尝试,但我仍然无法弄清楚。

;WITH user_count
AS
(
SELECT * FROM Tree WHERE Depth Is Null AS null_users
UNION ALL
WHILE EXISTS () 
UPDATE T SET T.depth = P.Depth + 1, 
T.Lineage = P.Lineage + Ltrim(Str(T.ParentNode,6,0)) + '/' 
FROM Tree AS T 
INNER JOIN Tree AS P ON (T.ParentNode=P.Node) 
WHERE P.Depth>=0 
AND P.Lineage Is Not Null 
AND T.Depth Is Null
)

最佳答案

在 MySQL-8.0 中:

select version();
| version() |
| :-------- |
| 8.0.13    |
CREATE TABLE tree (
  `Node` VARCHAR(3),
  `ParentNode` VARCHAR(3),
  `EmployeeID` INTEGER,
  `Depth` INTEGER,
  `Lineage` VARCHAR(16)
);
INSERT INTO tree
  (`Node`, `ParentNode`, `EmployeeID`, `Depth`, `Lineage`)
VALUES
  ('100', NULL, '1001', 0, '/'),
  ('101', '100', '1002', NULL, NULL),
  ('102', '101', '1003', NULL, NULL),
  ('103', '102', '1004', NULL, NULL),
  ('104', '102', '1005', NULL, NULL),
  ('105', '102', '1006', NULL, NULL);
WITH RECURSIVE prev AS (
SELECT * FROM tree WHERE ParentNode IS NULL
UNION
SELECT t.Node,t.ParentNode,t.EmployeeID,p.Depth + 1 as Depth, CONCAT(p.Lineage, t.ParentNode, '/')
FROM tree t
JOIN prev p ON t.ParentNode = p.Node
)
SELECT * FROM prev;
Node | ParentNode | EmployeeID | Depth | Lineage      
:--- | :--------- | ---------: | ----: | :------------
100  | null       |       1001 |     0 | /            
101  | 100        |       1002 |     1 | /100/        
102  | 101        |       1003 |     2 | /100/101/    
103  | 102        |       1004 |     3 | /100/101/102/
104  | 102        |       1005 |     3 | /100/101/102/
105  | 102        |       1006 |     3 | /100/101/102/
WITH RECURSIVE prev AS (
SELECT * FROM tree WHERE ParentNode IS NULL
UNION
SELECT t.Node,t.ParentNode,t.EmployeeID,p.Depth + 1 as Depth, CONCAT(p.Lineage, t.ParentNode, '/')
FROM prev p
JOIN tree t ON t.ParentNode = p.Node
)
UPDATE tree t, prev p
SET t.Depth=p.Depth, t.Lineage=p.Lineage
WHERE t.Node=p.Node;
SELECT * FROM tree
Node | ParentNode | EmployeeID | Depth | Lineage      
:--- | :--------- | ---------: | ----: | :------------
100  | null       |       1001 |     0 | /            
101  | 100        |       1002 |     1 | /100/        
102  | 101        |       1003 |     2 | /100/101/    
103  | 102        |       1004 |     3 | /100/101/102/
104  | 102        |       1005 |     3 | /100/101/102/
105  | 102        |       1006 |     3 | /100/101/102/

mysql8.0 db<>fiddle here

MariaDB 确实 not yet supported UPDATE in CTEs

但是它可以使用临时表来执行,例如:

CREATE TEMPORARY TABLE newtree AS
WITH RECURSIVE prev AS (
SELECT * FROM tree WHERE ParentNode IS NULL
UNION
SELECT t.Node,t.ParentNode,t.EmployeeID,p.Depth + 1 as Depth, CONCAT(p.Lineage, t.ParentNode, '/')
FROM tree t JOIN prev p ON t.ParentNode = p.Node
)
SELECT Node,Depth,Lineage FROM prev;
UPDATE tree t, newtree p SET t.Depth=p.Depth, t.Lineage=p.Lineage WHERE t.Node=p.Node;
SELECT * from tree
Node | ParentNode | EmployeeID | Depth | Lineage      
:--- | :--------- | ---------: | ----: | :------------
100  | null       |       1001 |     0 | /            
101  | 100        |       1002 |     1 | /100/        
102  | 101        |       1003 |     2 | /100/101/    
103  | 102        |       1004 |     3 | /100/101/102/
104  | 102        |       1005 |     3 | /100/101/102/
105  | 102        |       1006 |     3 | /100/101/102/

MariaDB-10.3 db<>fiddle here

关于MySQL - 当代码片段中存在时会抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54583713/

相关文章:

php - 从mysql中检索数据并显示在html表中

mysql - MySql表引擎从innoDB切换到NDB后性能下降

mysql - AWS lambda 中的 SQL 查询语法错误;字 "Dec"不起作用,但 "Dev"工作正常

sql - 在递归 SQL 表中查找最低公共(public)父级

php - 更新特定列等于其他表

sql - 子查询中是否允许 order by 子句

mysql - 如何检索表中昨天插入的记录?

mysql - 如何从mysql表的前3行中获取最小值

sql - Postgres : convert single row to multiple rows (unpivot)

c# - 合并 gridview 行并消除重复项