MySql:按父子顺序排序

Posted

技术标签:

【中文标题】MySql:按父子顺序排序【英文标题】:MySql: ORDER BY parent and child 【发布时间】:2012-11-14 15:59:09 【问题描述】:

我有一张这样的桌子:

+------+---------+-
| id   | parent  |
+------+---------+
| 2043 |    NULL |
| 2044 |    2043 |
| 2045 |    2043 |
| 2049 |    2043 |
| 2047 |    NULL |
| 2048 |    2047 |
| 2049 |    2047 |
+------+---------+

它显示了一个简单的 2 级“父子”关联。我如何通过 SELECT 语句订购以获取上面列表中的顺序,这意味着:第一个父母,第一个父母的孩子,第二个父母,第二个父母的孩子等等(如果我有,我可以添加为孩子们订购……我希望)。是否可以不添加排序字段?

【问题讨论】:

我看到 id=2043 两次;请修复。 【参考方案1】:

包括按 id 排序子项:

ORDER BY COALESCE(parent, id), parent IS NOT NULL, id

SQL Fiddle example

解释:

COALESCE(parent, id):首先按(有效地组合在一起)父母的 id 进行排序。 parent IS NOT NULL:将父行放在组的顶部 id:最后对所有孩子进行排序(同一个父母,并且parent不为空)

【讨论】:

这似乎是 sqlfiddle 的问题。试试这个sqlfiddle.com/#!9/63640/1【参考方案2】:

如果您的表使用0 而不是null 来指示没有父项的条目:

id   | parent
-------------
1233 | 0
1234 | 1233
1235 | 0
1236 | 1233
1237 | 1235

使用greatest 代替coalesce 并检查值不等于0

ORDER BY GREATEST(parent, id), parent != 0, id

【讨论】:

这不起作用,我不得不使用这个:ORDER BY COALESCE(IF(parent_id=0,NULL,parent_id), id), parent_id IS NOT NULL, id;【参考方案3】:

上面的解决方案对我不起作用,我的表使用 0 而不是 NULL。 我找到了另一个解决方案:您在查询中创建一个包含串联父 ID 和子 ID 的列,您可以通过它对结果进行排序。

SELECT CONCAT(IF(parent = 0,'',CONCAT('/',parent)),'/',id) AS gen_order
FROM table 
ORDER BY gen_order

【讨论】:

【参考方案4】:

此问题仍显示为首批搜索结果之一。所以我想分享一个我的解决方案,希望它能帮助更多的人。当您有一个包含多个父子关系级别的表时,这也将起作用。虽然这是一个相当缓慢的解决方案。顶层有 NULL 作为父级。

+---------+---------+
| id      | parent  |
+---------+---------+
| 1       | NULL    |
| 2       | 1       |
| 3       | 1       |
| 4       | 2       |
+---------+---------+

在我的方法中,我将使用一个递归调用自身的过程,并继续在路径前面加上所请求的id 的父级,直到它到达NULL 父级。

DELIMITER $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `PATH`(IN `input` INT, OUT `output` VARCHAR(128))
BEGIN

  DECLARE _id INT;
  DECLARE _parent INT;
  DECLARE _path VARCHAR(128);

  SET `max_sp_recursion_depth` = 50;

  SELECT `id`, `parent`
  INTO _id, _parent
  FROM `database`.`table`
  WHERE `table`.`id` = `input`;

  IF _parent IS NULL THEN
    SET _path = _id;
  ELSE
    CALL `PATH`(_parent, _path);
    SELECT CONCAT(_path, '-', _id) INTO _path;
  END IF;

  SELECT _path INTO `output`;

END $$
DELIMITER ;

要在 ORDER BY 子句中使用结果,您还需要一个 FUNCTION 来包装 PROCEDURE 的结果。

DELIMITER $$
CREATE DEFINER=`root`@`localhost` FUNCTION `GETPATH`(`input` INT) RETURNS VARCHAR(128)
BEGIN

  CALL `PATH`(`input`, @path);
  RETURN @path;

END $$
DELIMITER ;

现在我们可以使用递归路径对表格的顺序进行排序。在一个有 10000 行的表上,在我的工作站上只需要一秒钟多一点的时间。

SELECT `id`, `parent`, GETPATH(`id`) `path` FROM `database`.`table` ORDER BY `GETPATH`(`id`);

示例输出:

+---------+---------+---------------+
| id      | parent  | path          |
+---------+---------+---------------+
| 1       | NULL    | 1             |
| 10      | 1       | 1-10          |
| 300     | 10      | 1-10-300      |
| 301     | 300     | 1-10-300-301  |
| 302     | 300     | 1-10-300-302  |
+---------+---------+---------------+
5 rows in set (1,39 sec)

【讨论】:

在重新阅读最初的问题后,我发现它只是询问 2 级后代,其中一个父母可能有多个后代(兄弟姐妹)。这个答案超出了范围,涵盖了我需要的 N 级后代的情况

以上是关于MySql:按父子顺序排序的主要内容,如果未能解决你的问题,请参考以下文章

父子组件按啥顺序呈现?

子类继承父类,子类执行的时候,父子类的执行顺序?

父子组件生命周期执行顺序

在树状通用列表中按字母数字顺序对子项进行排序的扩展方法

vue父子组件加载顺序

react 父子组件执行顺序