EXPLAIN EXTENDED

How to create fast database queries

Hierarchical queries in MySQL: finding leaves

Comments enabled. I *really* need your comment

In this article, we will find the leaves of the hierarchy tree.

A row is a leaf in a hierarchy tree if it has no children.

In Oracle, there is a speical pseudocolumn that tests if a given row is a leaf in a CONNECT BY query. Surprisingly, it's called CONNECT_BY_ISLEAF.

This pseudocolumn is quite straightforward: it returns 1 when a row is a leaf, 0 otherwise.

This pseudocolumn is quite easy to emulate in MySQL, and we can do it even without using user-defined functions:

SELECT  CONCAT(REPEAT('    ', lvl - 1), hi.id) AS treeitem,
hierarchy_sys_connect_by_path('/', hi.id) AS path,
parent, lvl,
CASE
WHEN lvl >= @maxlevel THEN 1
ELSE COALESCE(
(
SELECT  0
FROM    t_hierarchy hl
WHERE   hl.parent = ho.id
LIMIT 1
), 1)
END AS is_leaf
FROM    (
SELECT  hierarchy_connect_by_parent_eq_prior_id_with_level(id, @maxlevel) AS id,
CAST(@level AS SIGNED) AS lvl
FROM    (
SELECT  @start_with := 1,
@id := @start_with,
@level := 0,
@maxlevel := 2
) vars, t_hierarchy
WHERE   @id IS NOT NULL
) ho
JOIN    t_hierarchy hi
ON      hi.id = ho.id
treeitem path parent lvl is_leaf
2 1/2 1 1 0
    7 1/2/7 2 2 1
    8 1/2/8 2 2 1
    9 1/2/9 2 2 1
    10 1/2/10 2 2 1
    11 1/2/11 2 2 1
3 1/3 1 1 0
    12 1/3/12 3 2 1
    13 1/3/13 3 2 1
    14 1/3/14 3 2 1
    15 1/3/15 3 2 1
    16 1/3/16 3 2 1
4 1/4 1 1 0
    17 1/4/17 4 2 1
    18 1/4/18 4 2 1
    19 1/4/19 4 2 1
    20 1/4/20 4 2 1
    21 1/4/21 4 2 1
5 1/5 1 1 0
    22 1/5/22 5 2 1
    23 1/5/23 5 2 1
    24 1/5/24 5 2 1
    25 1/5/25 5 2 1
    26 1/5/26 5 2 1
6 1/6 1 1 0
    27 1/6/27 6 2 1
    28 1/6/28 6 2 1
    29 1/6/29 6 2 1
    30 1/6/30 6 2 1
    31 1/6/31 6 2 1
30 rows fetched in 0.0020s (0.0628s)

This expression works as follows:

  1. It tests if the current row level hits the maximum level constraint. If it does, the expression returns 1 immediately, as even if there are children in the table itself, their level would exceed the maximum level value and, therefore, they would not be returned by hierarchy_connect_by_parent_eq_prior_id_with_level
  2. If the level is OK, the expression selects 0 for the first child of the current row. If there is no child, then the row is a leaf, and the expression returns 1

This is an efficient way to do the check, as the subquery performs just a quick one row index scan without costly function calls.

To be continued.

Written by Quassnoi

March 20th, 2009 at 11:00 pm

Posted in MySQL

Leave a Reply