1

I have a single table 'tags' with the following fields (id, parent_id, name). Now I've set a limit of 3 levels in the hierarchy, i.e.: parent > child > subchild. A subchild cannot have a further child. So I want a query to retrieve records such as:

Parent-data (if parent has child) child-data (if child has subchild) subchild-data

1 Answer 1

1

Try something like:

SELECT tparent.id   AS parent_id, 
       tparent.name AS parent_name, 
       tchild1.id   AS child_id, 
       tchild1.name AS child_name, 
       tchild2.id   AS subchild_id, 
       tchild2.name AS subchild_name 
FROM   tags tparent 
       LEFT JOIN tags tchild1 
              ON tparent.id = tchild1.parent_id 
       LEFT JOIN tags tchild2 
              ON tchild1.id = tchild2.parent_id 

According to your comment, you're looking for the following output:

ID | PARENT | NAME
 1 |      0 | family
 2 |      1 | male
 3 |      2 | boy1
 4 |      2 | boy2
 5 |      1 | female
 6 |      5 | girl1

I will assume that the ids won't always be in this order, cause if they are, problem solved :)

I'm not sure you can achieve this directly in SQL without adding some additional information that will be used for ordering. For instance, you could add another column where you'd concatenate the ids of parent-child-subchild. Something like:

-- parent
SELECT CONCAT(LPAD(id, 6, '0'), '-000000-000000') AS order_info,
       id                                         AS id,
       parent_id                                  AS parent,
       name                                       AS name
FROM   tags
WHERE  parent_id = 0
UNION
-- child
SELECT CONCAT_WS('-', LPAD(tparent.id, 6, '0'), 
                      LPAD(tchild1.id, 6, '0'),
                      '000000'),
       tchild1.id,
       tparent.id,
       tchild1.name
FROM   tags tparent
       INNER JOIN tags tchild1
               ON tparent.id = tchild1.parent_id
WHERE  tparent.parent_id = 0
UNION
-- subchild
SELECT CONCAT_WS('-', LPAD(tparent.id, 6, '0'), 
                      LPAD(tchild1.id, 6, '0'),
                      LPAD(tchild2.id, 6, '0')),
       tchild2.id,
       tchild1.id,
       tchild2.name
FROM   tags tparent
       INNER JOIN tags tchild1
               ON tparent.id = tchild1.parent_id
       INNER JOIN tags tchild2
               ON tchild1.id = tchild2.parent_id
ORDER  BY 1

See the fiddle illustrating this.

Here, I'm formatting the ids to keep ordering coherent. That implies to know the maximum length of the ids (I used a length of 6 here), which is trivial to guess from the id field type.

Sign up to request clarification or add additional context in comments.

6 Comments

Yes I have used this but this gets me a complete node in a single record. i.e. : parent -> child 1 -> subchild parent -> child 2 -> subchild However I wish to retrieve records like this: Parent child 1 subchild child 2 subchild
Please add a sample output in your question to make things clear, but if I understand your requirements, this is something you'd better do on your presentation layer rather than in SQL.
Following is the output that I would like to generate. When I search for a tag named "Family" it should retrieve me its child and sub child in the following order. Output: id , parent, name 1 , 0, family 2 , 1, male 3, 2, boy1 4, 2, boy2 5 , 1, female 6, 5, girl1 I can perform this in the presentation layer by using the join solution but for that I will have to organize my data with a few checks. However can you please help me if there's a possibility to generate the output above. Thanks in advance
I edited my answer. The sample data in comments are never easy to read, you should put them in your question body instead, as they're directly linked to your requirements. Plus, in its current form, your question does not really describe that.
Perfect, just what I was looking for. Thanks for the advice, I'll keep that in mind. By the way can you please tell me the efficiency of this query? vs efficiency of this if I use joins and perform the tree organization in the presentation layer? Thanks
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.