I was reading through this page https://www.sqlteam.com/articles/more-trees-hierarchies-in-sql (great article on managing hierarchical data in SQL) and following along in MySQL and was trying to run this SQL snippet.
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
Except I get the following error:
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
I’ve tried adding in BEGIN
, END
, END WHILE
etc from suggestions in While exists in mysql but still not working.
You can try and run the above snippet in an SQL validator (https://www.eversql.com/sql-syntax-check-validator/ is a good free online one) and see the error.
I’m looking for suggestions on why the above snippet doesn’t work from the blog / what can be changed so the same result is achieved.
Update – Adding in more data
Thanks @danblack for the suggestion to add more data to make it a verifiable example.
My current table
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
What it should look like after the snippet is run
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 pointed out that the snippet is Microsoft SQL, not MySQL and should use a recursive CTE to do this. This is my attempt but I still can’t figure it out.
;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 )
Advertisement
Answer
In 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 treeNode | 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 does not yet supported UPDATE in CTEs
However it can be performed with a temporary table like:
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 treeNode | 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/