假设我有这个例子的内容:
CREATE TABLE NaiveTable
{
id BIGINT NOT NULL,
parentId BIGINT NULL,
name VARCHAR(20) NULL,
CONSTRAINT hierarchy FOREIGN KEY (parentId) REFERENCES NaiveTable(id)
PRIMARY KEY (id)
}
作为注释,parentId是对NaiveTable的id的引用(如果我错过了确切的语法)。
数据在这些
的某些地方+---------+----------+----------+
| id | parentId | name |
+---------+----------+----------+
| 1 | null | node1 |
+---------+----------+----------+
| 2 | 1 | node2 |
+---------+----------+----------+
| 3 | 1 | node3 |
+---------+----------+----------+
| 4 | 2 | node4 |
+---------+----------+----------+
列名包含一些未分隔的标签。我正在寻找一种在MySQL表上构建SQL查询的方法,其中所有信息将被平铺并按层次排序,如下所示:
node 1, depth 0
node 2, depth 1
node 4, depth 2
node 3, depth 1
注意:我无法以任何方式修改数据库架构。我只能创建SQL查询。此外,我不能使用WITH
关键字,因为MySQL不支持它。有没有办法进行这样的查询?
但是,深度2或更高的任何解决方案都被视为足够好。
编辑:如果你喜欢尝试,这里是SQL fiddle。)
答案 0 :(得分:1)
如果数据库的模式是固定的并且您无法添加/编辑任何表,那么您所能做的就是在内存中构建树(使用某种编程语言),然后尝试计算每个节点在内存中的深度。所以我的答案是,只用一个查询就无法生成所需的输出!
但是,如果您可以修改数据库的架构,那么您可能需要检查this。
答案 1 :(得分:0)
这是一个小的递归存储过程,它应该适用于任何深度。这是我的第一个存储过程,所以请让我知道如何改进它。
DROP PROCEDURE IF EXISTS tree_reader;
DELIMITER $$
CREATE PROCEDURE tree_reader(IN parent INT, IN depth INT) READS SQL DATA
BEGIN
DECLARE id_val INT;
DECLARE name_val VARCHAR(255);
DECLARE _table_name VARCHAR(255);
DECLARE no_more_rows BOOLEAN;
DECLARE cur CURSOR FOR
SELECT id, name
FROM tree
WHERE IF(parent IS NULL, parentid IS NULL, parentid = parent);
DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_rows = TRUE;
-- create temporary table on outer call only --
IF depth=0 THEN
DROP TABLE IF EXISTS _tree;
CREATE TEMPORARY TABLE _tree (id INT, name VARCHAR(255), depth INT);
END IF;
OPEN cur;
-- loop with recursion --
tree_loop: LOOP
FETCH cur INTO id_val, name_val;
IF no_more_rows THEN LEAVE tree_loop; END IF;
INSERT INTO _tree VALUES (id_val, name_val, depth);
CALL tree_reader(id_val, depth + 1);
END LOOP tree_loop;
CLOSE cur;
-- output results on outer call only --
IF depth=0 THEN
SELECT * FROM _tree;
DROP TABLE _tree;
END IF;
END
$$
DELIMITER ;
一些注意事项:
请致电程序:CALL tree_reader(NULL, 0);
您可以使用任何父节点ID,但第二个参数始终为0
。在实践中,我可能会添加一个不带参数的包装程序,并给出整个树。
您必须设置递归限制才能正常工作:SET max_sp_recursion_depth = 6;
(我随意选择了6个)。