在一个SQL查询中获取所有父行

时间:2010-03-14 10:24:47

标签: mysql sql hierarchical-data

我有一个简单的MySQL表,其中包含一个类别列表,级别由parent_id确定:

id  name    parent_id
---------------------------
1   Home        0
2   About       1
3   Contact     1
4   Legal       2
5   Privacy     4
6   Products    1
7   Support     1

我正试图制作面包屑痕迹。所以我有孩子的'id',我想得到所有可用的父母(迭代链,直到我们达到0“Home”)。可以有任何数量或子行进入无限深度。

目前我正在为每个父级使用SQL调用,这很麻烦。 SQL中是否有一种方法可以在一个查询中完成所有操作?

9 个答案:

答案 0 :(得分:56)

改编自here

SELECT T2.id, T2.name
FROM (
    SELECT
        @r AS _id,
        (SELECT @r := parent_id FROM table1 WHERE id = _id) AS parent_id,
        @l := @l + 1 AS lvl
    FROM
        (SELECT @r := 5, @l := 0) vars,
        table1 h
    WHERE @r <> 0) T1
JOIN table1 T2
ON T1._id = T2.id
ORDER BY T1.lvl DESC

@r := 5是当前页面的页码。结果如下:

1, 'Home'
2, 'About'
4, 'Legal'
5, 'Privacy'

答案 1 :(得分:3)

Mark Byers的精彩回答!

派对可能有点晚了,但是如果你还想在id = parent_id时阻止无限循环(即数据以某种方式被破坏),你可以像这样扩展答案:

SELECT T2.id, T2.name
FROM (
    SELECT
        @r AS _id,
        @p := @r AS previous
        (SELECT @r := parent_id FROM table1 WHERE id = _id) AS parent_id,
        @l := @l + 1 AS lvl
    FROM
        (SELECT @r := 5, @p := 0, @l := 0) vars,
        table1 h
    WHERE @r <> 0 AND @r <> @p) T1
JOIN table1 T2
ON T1._id = T2.id
ORDER BY T1.lvl DESC

答案 2 :(得分:2)

接受的答案具有递归检索子用户的所有父用户的最佳解决方案。我已根据需要对其进行了修改。

对于 MySQL 5.5、5.6 和 5.7

SELECT @r AS user_id, 
   (SELECT @r := parent_id FROM users_table WHERE id = user_id) AS parent_id, 
   @l := @l + 1 AS level 

   FROM (SELECT @r := 9, @l := 0) val, users_table WHERE @r <> 0 

注意:@r := 9。其中 9 是子用户的 ID。

See fiddle here


上述查询在 MySQL 8 中已弃用。所以这里是 MySQL 8.0 的查询

with recursive parent_users (id, parent_id, level) AS (
  SELECT id, parent_id, 1 level
  FROM users_table
  WHERE id = 9
  union all
  SELECT t.id, t.parent_id, level + 1
  FROM users_table t INNER JOIN parent_users pu
  ON t.id = pu.parent_id
)
SELECT * FROM parent_users;

注意:id = 9。其中 9 是子用户的 id。

See fiddle here

答案 3 :(得分:1)

除上述解决方案外:

post
-----
id
title
author

author
------
id
parent_id
name


[post]

id  | title | author |  
----------------------
1   | abc   | 3      |


[author]

| id    | parent_id | name  |   
|---------------------------|
| 1     | 0         | u1    |
| 2     | 1         | u2    |
| 3     | 2         | u3    |
| 4     | 0         | u4    |

包括父母在内的作者可以访问该帖子。

我想检查作者是否有权访问该帖子。

解决方案:

给出帖子作者的id并返回其所有作者和作者的父母

SELECT T2.id, T2.username 
FROM (
    SELECT @r AS _id, 
        (SELECT @r := parent_id FROM users WHERE id = _id) AS parent_id,
        @l := @l + 1
    FROM
        (SELECT @r := 2, @l := 0) vars, 
        users h     
    WHERE @r <> 0) T1 JOIN users T2 
ON T1._id = T2.id;

@r:= 2 =&gt;为@r变量赋值。

答案 4 :(得分:0)

我认为,使用一个查询没有简单的方法。

我建议您查看Nested Sets,这似乎符合您的需求。

答案 5 :(得分:0)

如果您有子弹而不是id,则只需运行子查询以查找子类别的id。
表格-类别
| id | parentId |鼻涕虫|
| ------------------------- |
| 1 || 0 | u1 ||
| 2 || 1 | u2 ||
| 3 || 2 | u3 ||
| 4 || 0 | u4 ||

SELECT T2.id, T2.slug
FROM (
    SELECT
        @r AS _id,
        (SELECT @r := parentId FROM categories WHERE id = _id) AS parentId,
        @l := @l + 1 AS lvl
    FROM
        (SELECT @r := (SELECT id FROM categories WHERE slug = 'u3'), @l := 0) vars,
        categories h
    WHERE @r <> 0) T1
JOIN categories T2
ON T1._id = T2.id
ORDER BY T1.lvl DESC

答案 6 :(得分:0)

我以前面的答案为例,使内容更易读懂。

SELECT  @org_id as id,
    (SELECT name FROM test.organizations WHERE id = @org_id) as name,
    (SELECT @org_id := parent_id FROM test.organizations WHERE id = @org_id) AS parent_id
FROM (SELECT @org_id := 4) vars, test.organizations org
WHERE @org_id is not NULL
ORDER BY id;

执行结果如下:

result of execution

(只是为了快速) 要自己检查它,您需要将问题的值输入数据库test的表organizations

CREATE TABLE organizations(
id        int(11) NOT NULL AUTO_INCREMENT,
name      varchar(45) DEFAULT NULL,
parent_id int(11)     DEFAULT NULL,
PRIMARY KEY (id));

insert into organizations values(1, "home", null);
insert into organizations values(2, "about", 1);
insert into organizations values(3, "contact", 1);
insert into organizations values(4, "legal", 2);
insert into organizations values(5, "privacy", 4);
insert into organizations values(6, "products", 1);
insert into organizations values(7, "support", 1);

答案 7 :(得分:0)

在我为自己的分层表开发解决方案时,我查看了 WP 多级类别模型。基于此处提供的出色答案,我进行了此查询以获取 Wordpress 数据库中的父类别。我不是这方面的专家,但这对我有用,可能对寻找此类答案的人有所帮助。

  SELECT T2.term_id,T3.name,T3.slug
    FROM (
        SELECT
            @r AS _id,
            @p := @r AS previous,
            (SELECT @r := parent FROM wp_term_taxonomy WHERE term_id = _id AND taxonomy = 'category') AS parent_id,
            @l := @l + 1 AS lvl
        FROM
            (SELECT @r := 8, @p := 0, @l := 0) vars,
            wp_term_taxonomy h
        WHERE @r <> 0 AND @r <> @p) T1
    JOIN wp_term_taxonomy T2 ON T1._id = T2.term_id AND T2.taxonomy = 'category'
    LEFT JOIN wp_terms T3 ON T3.term_id = T2.term_id
    ORDER BY T1.lvl DESC

答案 8 :(得分:-1)

AFAIK no。

This Sitepoint article可能对您有帮助。

您可以使用一个查询检索所有元素,将其存储在数组中然后进行迭代, 正如herehere

所述
相关问题