我有一个MySQL表,如下所示:
现在,我想有一个简单的MySQL查询,只需向其提供ID [例如说id=19],然后就应该获取其所有子ID [即结果应具有ID ‘20,21,22’]…。
孩子的等级未知;它可能会有所不同....
我知道如何使用for循环…但是如何使用单个MySQL查询实现相同的目标?
对于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字符串由于某种原因会产生虚假的值,也只能调用该函数以确保此条件始终为真。
总而言之,人们可能会发现这些假设过于冒险,无法依靠。该文档警告:
您可能会得到期望的结果,但是不能保证涉及用户变量的表达式的求值顺序是不确定的。daccess-ods.un.org daccess-ods.un.org
因此,即使它与上面的查询一致地工作,评估顺序仍可能会更改,例如,当您添加条件或将此查询用作较大查询中的视图或子查询时。这是一个“功能”,将在将来的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包含层次结构信息的值(路径),事情就会变得容易得多。例如,在您的情况下,可能看起来像这样:
然后,您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;
在where你想要的条件指定哪个家长要检索的后裔。您可以根据需要将查询扩展到更多级别。
我有一个MySQL表,如下所示: 现在,我想有一个MySQL查询,我只需向它提供id(例如),然后我应该获得它的所有子id(即,结果应该有id'20、21、22']... 不知道孩子的等级;它可以变化.... 我知道如何使用循环来实现...但是如何使用单个MySQL查询实现相同的功能呢?
我有一个父子关系数据库。数据如下所示,但可以以任何方式呈现(字典、列表列表、JSON等)。 我需要的输出是一个层次化的JSON树,它将用d3呈现。数据中有离散的子树,我将附加到根节点。所以我需要递归地遍历链接,并建立树结构。我最多只能遍历所有人并附加他们的孩子,但我不知道如何进行高阶链接(例如,如何将有孩子的人附加到其他人的孩子)。这类似于这里的另一个问题,但我无法提前知道根节点,因此无法实现公认
问题内容: 我有一组按层次结构组织的数据,应该可以增长到任意大小。我需要检索整个树,但是我无法弄清楚如何仅使用SQL来完成。我当前的解决方案是创建一个临时表,并使用递归函数依次查询树的分支,然后将结果存储在临时表中,随后我再次对其进行查询以产生所需的结果。 我的问题是,从本质上讲,我正在执行的联接正确吗?构造一个中间表,然后查询结果。似乎应该有一种使用联接的方法,但是MySQL文档仅涵盖检索有限深
问题内容: 我有一个像这样设置的物料清单表: item-parent 显示物料清单的最终结果是这样显示的: 最终结果也可能是多级的,如下所示: 它可以无限进行: 现在,我要么只是从数据库中获得1级: 或从表中拉出每一行,并使用递归函数仅对所需行进行排序,但这显然效率不高,因为我可能只需要10行,但我拉出10,000条记录。递归函数的输出将只创建一个像这样的树: 我所知道的是,我从项目1开始。项目5
本文向大家介绍使用递归[JavaScript]创建层次结构,包括了使用递归[JavaScript]创建层次结构的使用技巧和注意事项,需要的朋友参考一下 示例 输出
问题内容: 如何在MySql中运行此查询? 它会显示如下错误消息: 问题答案: 该语句/方法适用于PostgreSQL和Sybase(我想可能还有更多),所以也许您可以看一下: http://www.artfulsoftware.com/mysqlbook/sampler/mysqled1ch20.html 它应该向您展示一些使用MySQL的方法(以及PHP中的一两个方法,我只知道它不在您的标签列