开发者社区> 问答> 正文

如何创建MySQL分层递归查询

我有一个MySQL表,如下所示:

id | name | parent_id 19 | category1 | 0 20 | category2 | 19 21 | category3 | 20 22 | category4 | 21 ...... 现在,我想有一个简单的MySQL查询,只需向其提供ID [例如说'ID = 19'],然后就应该获取其所有子ID [即结果应具有ID '20,21,22']。 ...此外,孩子的等级也不知道它会有所不同...

另外,我已经有了使用for循环的解决方案.....如果可能的话,让我知道如何使用单个MySQL查询来实现相同的解决方案。

展开
收起
保持可爱mmm 2020-05-08 10:14:43 842 0
1 条回答
写回答
取消 提交回答
  • 对于MySQL 8+:使用递归with语法。 对于MySQL 5.x:使用内联变量,路径ID或自联接。

    MySQL 8+ with recursive cte (id, name, parent_id) as ( select id, name, parent_id from products where parent_id = 19 union all select p.id, p.name, p.parent_id from products p inner join cte on p.parent_id = cte.id ) select * from cte; 中指定的值parent_id = 19应设置为id您要选择其所有后代的父级的。

    MySQL 5.x 对于不支持通用表表达式的MySQL版本(最高5.7版),您可以通过以下查询来实现:

    select id, name, parent_id from (select * from products order by parent_id, id) products_sorted, (select @pv := '19') initialisation where find_in_set(parent_id, @pv) and length(@pv := concat(@pv, ',', id)) 这是一个小提琴。

    在此,@pv := '19'应将中指定的值设置为id要选择其所有后代的父级的值。

    如果父母有多个孩子,这也将起作用。但是,要求每个记录都满足条件parent_id < id,否则结果将不完整。

    查询中的变量分配 该查询使用特定的MySQL语法:在执行过程中分配和修改变量。对执行顺序进行了一些假设:

    该from子句首先被评估。这就是@pv初始化的地方。 where按照从from别名检索的顺序为每个记录评估该子句。因此,在这里将条件放在仅包括已将其父级标识为后代树的记录中(主要父级的所有后代都逐渐添加到中@pv)。 此where子句中的条件按顺序进行评估,一旦确定了总结果,评估就会中断。因此,第二个条件必须排在第二位,因为它将添加id到父列表,并且仅在id通过第一个条件时才应发生。length即使该pv字符串由于某种原因会产生虚假的值,也只能调用该函数以确保此条件始终为true 。 总而言之,人们可能会发现这些假设过于冒险,无法依靠。该文档警告:

    您可能会得到期望的结果,但这不能保证涉及用户变量的表达式的求值顺序不确定。

    因此,即使它与上面的查询一致地工作,评估顺序仍可能会更改,例如,当您添加条件或将此查询用作较大查询中的视图或子查询时。这是一个“功能”,将在将来的MySQL版本中删除:

    MySQL的早期版本使得可以在以外的语句中为用户变量赋值SET。MySQL 8.0支持此功能以实现向后兼容,但是在将来的MySQL版本中可能会删除该功能。

    如上所述,从MySQL 8.0开始,您应该使用递归with语法。

    效率 对于非常大的数据集,此解决方案可能会变慢,因为该find_in_set操作不是在列表中查找数字的最理想方法,当然,在列表大小与返回的记录数量相同数量级的列表中,查找方法肯定不是。

    选择1 :with recursive,connect by 越来越多的数据库执行SQL:1999 ISO标准WITH [RECURSIVE]语法的递归查询(如Postgres的8.4+,SQL Server的2005+,DB2,甲骨文11gR2的+,SQLite的3.8.4+,火鸟2.1+,H2,的HyperSQL 2.1.0+,Teradata的,MariaDB 10.2.2+)。从8.0版开始,MySQL也支持它。有关使用的语法,请参见此答案的顶部。

    一些数据库具有用于分层查找的替代非标准语法,例如Oracle,DB2,Informix,CUBRID和其他数据库CONNECT BY上可用的子句。

    MySQL 5.7版不提供这种功能。如果您的数据库引擎提供了这种语法,或者您可以迁移到该语法,那么这无疑是最佳选择。如果不是,则还考虑以下替代方法。

    备选方案2:路径样式标识符 如果您要分配id包含层次结构信息的值(路径),事情就会变得容易得多。例如,在您的情况下,可能如下所示:

    ID | NAME 19 | category1
    19/1 | category2
    19/1/1 | category3
    19/1/1/1 | category4
    然后,您select将如下所示:

    select id, name from products where id like '19/%' 选择3:重复的自我联接 如果您知道层次结构树的深度上限,则可以使用以下标准sql查询:

    select p6.parent_id as parent6_id, p5.parent_id as parent5_id, p4.parent_id as parent4_id, p3.parent_id as parent3_id, p2.parent_id as parent2_id, p1.parent_id as parent_id, p1.id as product_id, p1.name from products p1 left join products p2 on p2.id = p1.parent_id left join products p3 on p3.id = p2.parent_id left join products p4 on p4.id = p3.parent_id
    left join products p5 on p5.id = p4.parent_id
    left join products p6 on p6.id = p5.parent_id where 19 in (p1.parent_id, p2.parent_id, p3.parent_id, p4.parent_id, p5.parent_id, p6.parent_id) order by 1, 2, 3, 4, 5, 6, 7; 来源:stack overflow

    2020-05-08 10:15:00
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
One Box: 解读事务与分析一体化数据库 HybridDB for MySQL 立即下载
One Box:解读事务与分析一体化数据库HybridDB for MySQL 立即下载
如何支撑HTAP场景-HybridDB for MySQL系统架构和技术演进 立即下载

相关镜像