I have a MySQL table as shown below:
id | name | parent_id |
---|---|---|
19 | Category 1 | 0 |
20 | Category 2 | 19 |
twenty one | Category 3 | 20 |
twenty two | Category 4 | twenty one |
... | ... | ... |
Now, I want a MySQL query where I just provide the id [for example id=19
] and then I should get all its sub-ids [i.e. the result should have id '20,21,22 ']....
The hierarchy of children is unknown; it may vary...
I know how to do this using a for
loop...but how do I achieve the same thing using a single MySQL query?
For MySQL 8: Use recursion
Use
syntax.For MySQL 5.x: Use inline variables, path IDs, or self-joins.
MySQL 8
The value specified inparent_id = 19
should be set to theid
of the parent whose descendants you want to select.MySQL 5.x
For versions of MySQL (up to version 5.7) that do not support common table expressions, you can use the following query to achieve this:
This is a violin.
Here, the value specified in
@pv := '19'
should be set to theid
of the parent whose descendants you want to select. p>This will also work if the parent has multiple children. However, each record is required to meet the
parent_id condition, otherwise the result will be incomplete.
Variable assignment within query
This query uses specific MySQL syntax: variables are allocated and modified during execution. Some assumptions are made about the execution order:
from
clause first. This is where@pv
is initialized.where
clause is evaluated for each record in the order in which it was retrieved from thefrom
alias. Therefore, the condition set here only includes records whose parent has been identified as being in the descendant tree (all descendants of the primary parent will be incrementally added to@pv
).where
clause are evaluated sequentially, and evaluation is interrupted once the overall result is determined. So the second condition must be in second position because it adds the id to the parent list and this will only happen if the id passes the first condition. Thelength
function is called just to ensure that this condition is always true, even if thepv
string produces a false value for some reason.All in all, one may find these assumptions too risky to rely on. DocumentationWarning:
So even though it is consistent with the above query, the order of evaluation may still change, for example, when you add conditions or use this query as a view or subquery within a larger query. This is a "feature" that will be removed in a future MySQL version 一>:
As mentioned above, starting with MySQL 8.0, you should use recursive
with
syntax.efficiency
For very large data sets, this solution may be slow because the
find_in_set
operation is not the most ideal way to find numbers in a list, and certainly does not achieve the same goal as The number of records returned.Alternative 1:
Use recursion
,Connection
More and more databases implement SQL:1999 ISO standard
WITH [RECURSIVE]
Syntax for recursive queries (e.g. Postgres 8.4 , SQL Server 2005 a>, DB2, Oracle 11gR2 , SQLite 3.8.4 , Firebird 2.1 , H2 , HyperSQL 2.1.0 , Teradata, MariaDB 10.2.2 ). Starting with version 8.0, MySQL also supports it. See the top of this answer for the syntax to use.Some databases have alternative non-standard syntax for hierarchical lookups, such as the Oracle, DB2, Informix, CUBRID a> and other databases.
MySQL version 5.7 does not provide such functionality. When your database engine provides this syntax or you can migrate to a database engine that provides this syntax, then this is undoubtedly the best choice. If not, consider the following alternatives.
Alternative 2: Path Style Identifier
Things become much easier if you assign id values that contain hierarchical information (path). For example, in your case this might look like this:
Then your
selection
will look like this:Alternative 3: Repeated Self-Join
If you know the upper limit of the depth of the hierarchical tree, you can use the standard
sql
query like this:See thisfiddle
Thewhere
condition specifies which parent's descendants you want to retrieve. You can expand this query to more levels as needed.