如何只用 MySQL 遍历 Table 树
How to Loop through a Table Tree with only MySQL
要知道的事情:
- 我将此声明插入我们的报告软件中,所以我
没有使用 PHP 为我做循环的奢侈。
- 我不熟悉 MySQL 中的 LOOP 子句,我之前做了一些研究,但可以使用一些语法方面的帮助。
问题:
我将如何遍历此 MySQL 语句? (下面给出声明)
下面的语句现在有效,我还有进一步的 CASE WHEN
来添加它,但现在我正在尝试解决整个事情中最令人困惑的部分。
我需要遍历 MySQL 语句(或找到另一种方法来编写相同的内容),直到到达树的底部。为了说明我正在尝试做的事情:
假设我需要从顶部开始获取整棵树的下线。这意味着我必须为下面的每个人 运行 这个 MySQL 声明。
在我们目前的设置中,我像这样将他们上面的人的 ID
存储在记录中,要跟随记录向下,我必须给它上线 ID 和 return 具有该上线 ID 的所有记录,return 所有即时下线。
+---------+-------------+------+
| ID | Upline ID | Name |
+---------+-------------+------+
| 745753 | 654-64645-3 | John |
| 098678 | 916-59172-1 | Jill |
| 543272 | 866-99573-8 | Fred |
| 634543 | 126-97939-3 | Dean |
| 923461 | 734-84628-5 | Bill |
| 861345 | 643-01957-0 | Cris |
+---------+-------------+------+
这意味着对于集合中的每一行 returned,我必须按照 MySQL 语句分别沿着每个记录树向下,并对每一行 returned 执行相同的操作,导致 MySQL 语句成倍增加,直到,当我 运行 该记录的语句时,什么都没有 returned,所以我到达了下线的末尾。
无需进一步等待,这里是声明(我在 WHERE
子句中将其放在顶部 ID
的第一人称以开始声明):
SELECT wn_writing_number_cstm.title_c,
wn_writing_number.`name`,
preps_contracted_reps.first_name,
preps_contracted_reps.last_name,
cac_customize_agent_comp_cstm.commission_percentage_c,
wn_writing_number_cstm.id_c
FROM wn_writing_number
LEFT OUTER JOIN wn_writing_number_cac_customize_agent_comp_1_c ON wn_writing_number_cac_customize_agent_comp_1_c.wn_writing946b_number_ida = wn_writing_number.id
LEFT OUTER JOIN cac_customize_agent_comp ON wn_writing_number_cac_customize_agent_comp_1_c.wn_writing3148nt_comp_idb = cac_customize_agent_comp.id
LEFT OUTER JOIN cac_customize_agent_comp_cstm ON cac_customize_agent_comp.id = cac_customize_agent_comp_cstm.id_c
LEFT OUTER JOIN aos_products_cac_customize_agent_comp_1_c ON cac_customize_agent_comp_cstm.id_c = aos_products_cac_customize_agent_comp_1_c.aos_produca2b8nt_comp_idb
LEFT OUTER JOIN preps_contracted_reps_wn_writing_number_1_c ON preps_contracted_reps_wn_writing_number_1_c.preps_contracted_reps_wn_writing_number_1wn_writing_number_idb = wn_writing_number.id
LEFT OUTER JOIN preps_contracted_reps ON preps_contracted_reps_wn_writing_number_1_c.preps_cont9effed_reps_ida = preps_contracted_reps.id
LEFT OUTER JOIN wn_writing_number_cstm ON wn_writing_number_cstm.id_c = wn_writing_number.id
WHERE wn_writing_number_cstm.wn_writing_number_id_c = '53506bbe-008f-577c-2114-576b32e0ad11'
这里有一个查询生成器图来帮助说明这个模型:
最后,这就是这条语句实际上 returns,我需要再次 运行 这条语句两次,每行一次,每个行的 ID
我的 WHERE
子句中的那些记录:
+---------+-------------+------------+-------------------------------------+
| title_c | name | first_name | last_name | percent_c | id_c |
+---------+-------------+------------+-------------------------------------+
| A | MP-AB0682-16| Andrea | Donald | 10 | 823462345 |
| GA | RO-RM4619-16| Ronald | Yeller | 12 | 632811634 |
+---------+-------------+------------+-----------+-----------+-------------+
如需进一步说明,请发表评论。谢谢!
一个半伪代码答案来阐明我的方法(抱歉,没有时间获得更精确的解决方案,并且不要经常使用语法来准确记住它而无需查找):
DECLARE lastInsertCount INT;
DECLARE lastLayer INT;
CREATE TABLE `temp`
(
`layer` int,
[fields you want and parent's identifier]
);
INSERT INTO `temp`(`layer`, fields you want...)
SELECT 0, fields you want...
FROM theTable
WHERE [is "root" result]
;
SET lastLayer := 0;
SET lastInsertCount := 1;
LayerLoop: WHILE lastInsertCount > 0
INSERT INTO `temp`(`layer`, fields you want...)
SELECT lastLayer + 1, fields you want...
FROM theTable
WHERE parent_id IN (SELECT id FROM `temp` WHERE layer = lastLayer)
;
SET lastInsertCount := ROW_COUNT();
SET lastLayer := lastLayer + 1;
END WHILE LayerLoop;
SELECT fields you want...
FROM `temp`
;
DROP TABLE `temp`;
编辑:如果你允许 "cycles" 在树中,这将使其不是树(但我不得不担心它在坏数据中),你可以避免那些导致你无限循环的添加
AND id NOT IN (SELECT id FROM `temp`)
到 where 子句。
要知道的事情:
- 我将此声明插入我们的报告软件中,所以我 没有使用 PHP 为我做循环的奢侈。
- 我不熟悉 MySQL 中的 LOOP 子句,我之前做了一些研究,但可以使用一些语法方面的帮助。
问题:
我将如何遍历此 MySQL 语句? (下面给出声明)
下面的语句现在有效,我还有进一步的 CASE WHEN
来添加它,但现在我正在尝试解决整个事情中最令人困惑的部分。
我需要遍历 MySQL 语句(或找到另一种方法来编写相同的内容),直到到达树的底部。为了说明我正在尝试做的事情:
假设我需要从顶部开始获取整棵树的下线。这意味着我必须为下面的每个人 运行 这个 MySQL 声明。
在我们目前的设置中,我像这样将他们上面的人的 ID
存储在记录中,要跟随记录向下,我必须给它上线 ID 和 return 具有该上线 ID 的所有记录,return 所有即时下线。
+---------+-------------+------+
| ID | Upline ID | Name |
+---------+-------------+------+
| 745753 | 654-64645-3 | John |
| 098678 | 916-59172-1 | Jill |
| 543272 | 866-99573-8 | Fred |
| 634543 | 126-97939-3 | Dean |
| 923461 | 734-84628-5 | Bill |
| 861345 | 643-01957-0 | Cris |
+---------+-------------+------+
这意味着对于集合中的每一行 returned,我必须按照 MySQL 语句分别沿着每个记录树向下,并对每一行 returned 执行相同的操作,导致 MySQL 语句成倍增加,直到,当我 运行 该记录的语句时,什么都没有 returned,所以我到达了下线的末尾。
无需进一步等待,这里是声明(我在 WHERE
子句中将其放在顶部 ID
的第一人称以开始声明):
SELECT wn_writing_number_cstm.title_c,
wn_writing_number.`name`,
preps_contracted_reps.first_name,
preps_contracted_reps.last_name,
cac_customize_agent_comp_cstm.commission_percentage_c,
wn_writing_number_cstm.id_c
FROM wn_writing_number
LEFT OUTER JOIN wn_writing_number_cac_customize_agent_comp_1_c ON wn_writing_number_cac_customize_agent_comp_1_c.wn_writing946b_number_ida = wn_writing_number.id
LEFT OUTER JOIN cac_customize_agent_comp ON wn_writing_number_cac_customize_agent_comp_1_c.wn_writing3148nt_comp_idb = cac_customize_agent_comp.id
LEFT OUTER JOIN cac_customize_agent_comp_cstm ON cac_customize_agent_comp.id = cac_customize_agent_comp_cstm.id_c
LEFT OUTER JOIN aos_products_cac_customize_agent_comp_1_c ON cac_customize_agent_comp_cstm.id_c = aos_products_cac_customize_agent_comp_1_c.aos_produca2b8nt_comp_idb
LEFT OUTER JOIN preps_contracted_reps_wn_writing_number_1_c ON preps_contracted_reps_wn_writing_number_1_c.preps_contracted_reps_wn_writing_number_1wn_writing_number_idb = wn_writing_number.id
LEFT OUTER JOIN preps_contracted_reps ON preps_contracted_reps_wn_writing_number_1_c.preps_cont9effed_reps_ida = preps_contracted_reps.id
LEFT OUTER JOIN wn_writing_number_cstm ON wn_writing_number_cstm.id_c = wn_writing_number.id
WHERE wn_writing_number_cstm.wn_writing_number_id_c = '53506bbe-008f-577c-2114-576b32e0ad11'
这里有一个查询生成器图来帮助说明这个模型:
最后,这就是这条语句实际上 returns,我需要再次 运行 这条语句两次,每行一次,每个行的 ID
我的 WHERE
子句中的那些记录:
+---------+-------------+------------+-------------------------------------+
| title_c | name | first_name | last_name | percent_c | id_c |
+---------+-------------+------------+-------------------------------------+
| A | MP-AB0682-16| Andrea | Donald | 10 | 823462345 |
| GA | RO-RM4619-16| Ronald | Yeller | 12 | 632811634 |
+---------+-------------+------------+-----------+-----------+-------------+
如需进一步说明,请发表评论。谢谢!
一个半伪代码答案来阐明我的方法(抱歉,没有时间获得更精确的解决方案,并且不要经常使用语法来准确记住它而无需查找):
DECLARE lastInsertCount INT;
DECLARE lastLayer INT;
CREATE TABLE `temp`
(
`layer` int,
[fields you want and parent's identifier]
);
INSERT INTO `temp`(`layer`, fields you want...)
SELECT 0, fields you want...
FROM theTable
WHERE [is "root" result]
;
SET lastLayer := 0;
SET lastInsertCount := 1;
LayerLoop: WHILE lastInsertCount > 0
INSERT INTO `temp`(`layer`, fields you want...)
SELECT lastLayer + 1, fields you want...
FROM theTable
WHERE parent_id IN (SELECT id FROM `temp` WHERE layer = lastLayer)
;
SET lastInsertCount := ROW_COUNT();
SET lastLayer := lastLayer + 1;
END WHILE LayerLoop;
SELECT fields you want...
FROM `temp`
;
DROP TABLE `temp`;
编辑:如果你允许 "cycles" 在树中,这将使其不是树(但我不得不担心它在坏数据中),你可以避免那些导致你无限循环的添加
AND id NOT IN (SELECT id FROM `temp`)
到 where 子句。