0

Consider this is my table structure....

id | name        | parent_id
19 | category1   | 0
20 | category2   | 19
21 | category3   | 20
22 | category4   | 21
......

Now i want to fetch privious related rows with single mysql query. if i give `id=22' then query should return me id 21,20,19.

Also need to fetch (It can be a separate query) level wise data return. i.e. if i give id=22 then query should return only id 21 (first level). id 21,20 (secound level)...

Here's a similar link! Accept answer almost going to solve my problem but it only work assending order means when parent_id < id.

A portion of accepted answer :

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))
Shadow
  • 33,525
  • 10
  • 51
  • 64
Mustaque Ahmed
  • 125
  • 1
  • 3
  • 13

3 Answers3

1

You can create a stored function which will traverse the tree:

delimiter //
create function product_ancestors(in_id int) returns text reads sql data
begin
  declare current_id int default in_id;
  declare ancestor_ids text default null;

  while (current_id <> 0) do
    set current_id = (
      select parent_id
      from products
      where id = current_id
    );
    if (current_id <> 0)
      then set ancestor_ids = concat_ws(',', ancestor_ids, current_id);
    end if;
  end while;

  return ancestor_ids;
end //

delimiter ;

Use it with

select product_ancestors(22);

That will return a comma delimited string '21,20,19'.

See demo

Paul Spiegel
  • 30,925
  • 5
  • 44
  • 53
  • i have no idea where to store this function and how can i run. Can you please give me some hints sir? i use phpmyadmin for mysql GUI. – Mustaque Ahmed Sep 24 '19 at 07:53
  • @MustaqueAhmed In phpMyAdmin: Choose your DB. Click on "SQL" tab. Paste the first query. Then click "OK". Use the function with `select product_ancestors(22);` – Paul Spiegel Sep 24 '19 at 09:22
0

You can adapt the query from the link in your question by reversing things in it

select  id,
        name,
        parent_id, @pv 
from    (select * from products
         order by id desc) products_sorted,
        (select @pv := '21') initialisation
where   find_in_set(id, @pv)
and     length(@pv := concat(@pv, ',', parent_id))

Demo

Serg
  • 22,285
  • 5
  • 21
  • 48
-2

In MySQL 8+, you can use a recursive CTE:

with recursive cte as (
      select c.id, c.parent_id
      from categories c
      where c.id = 22
      union all
      select cte.id, c.parent_id
      from cte join
           categories c
           on c.id = cte.parent_id
     )
select *
from cte;

Use a join to bring in the names, if you need them as well.

Here is a db<>fiddle.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786