Mysql 递归查询获取父类别

Mysql recursive query to get parent category

我有 3 个 table:

  1. 用户
  2. user_groups

一个用户可以在多个(子)组中。它们存储在 user_groups table 中,像这样

+--------------+--------------+---------------+
| id           | user_id      | group_id      | 
+--------------+--------------+---------------+
| 1            | 1            | 23            |
+--------------+--------------+---------------+
| 2            | 2            | 24            |
-----------------------------------------------

现在在我的 groups table 中,排名靠前的类别是 parent_id = 0

+--------------+--------------+---------------+
| id           | parent_id    | name          | 
+--------------+--------------+---------------+
| 1            | 2            | Group 1.1     |
+--------------+--------------+---------------+
| 2            | 0            | Group 1       |
+--------------+--------------+---------------+
| 3            | 2            | Group 1.2     | 
+--------------+--------------+---------------+
| 4            | 3            | Group 1.2.1   |
+--------------+--------------+---------------+
| 5            | 2            | Group 1.3     |
+--------------+--------------+---------------+

现在我想构建一个查询,为我提供所有用户的所有父组。我做了一些关于递归查询的研究,我发现了这个特殊的 post: How to create a MySQL hierarchical recursive query

但是我不知道加入 tables 后应该如何处理这个问题。

这是我目前得到的:

SELECT
    `users`.`id`,
    `users`.`first_name`,
    `users`.`last_name`,
    `users`.`email`,
    `users`.`language`,
    `groups`.`name`,
    `groups`.`parent_id`
FROM `users`
    LEFT JOIN `user_groups`
        ON `user_groups`.`user_id` = `users`.`id`
    LEFT JOIN `groups`
        ON `groups`.`id` = `user_groups`.`group_id`
WHERE
    `users`.`created` 
    BETWEEN
        DATE_SUB(NOW(), INTERVAL 365 DAY) AND NOW()

但是这个查询只是让我得到了子组的名称和 ID。我要的是顶级群

感谢您的帮助!

典型的解决方案是创建一个存储函数,通过跟踪父系直到找到 parent_id = 0 的行,returns 任何给定组的顶级组。

然后您可以将该函数应用于用户所属的每个组,以及 select 不同的顶级组集。

像这样的东西应该适合你:

delimiter $$

drop function if exists get_top_level_group_id $$

create function get_top_level_group_id (p_group_id int) returns int
begin 
  declare v_return_val int;
  declare v_group_id int;
  declare v_parent_id int;
  declare continue handler for not found
    begin
      return -1;
    end;

  set v_group_id = p_group_id;
  set v_parent_id = p_group_id;

  while v_parent_id != 0 
  do 
    set v_group_id = v_parent_id;

    select `parent_id` 
    into v_parent_id 
    from `groups` 
    where id = v_group_id;
  end while;
  return v_group_id;
end $$

delimiter ;

然后您可以像这样更新查询以获取这些用户及其不同的顶级组:

SELECT DISTINCT
    `users`.`id`,
    `users`.`first_name`,
    `users`.`last_name`,
    `users`.`email`,
    `users`.`language`,
    get_top_level_group_id(`user_groups`.`group_id`) as top_level_group_id
FROM `users`
    LEFT JOIN `user_groups`
        ON `user_groups`.`user_id` = `users`.`id`
WHERE
    `users`.`created` 
    BETWEEN
        DATE_SUB(NOW(), INTERVAL 365 DAY) AND NOW()