【问题标题】:Add children rank to SQL result将子级添加到 SQL 结果
【发布时间】:2015-07-10 08:01:36
【问题描述】:

这是another question I just asked 的扩展。我在那里学习了如何正确编写 SQL 查询以获得所需的结果。但是当我尝试将它应用到我的实际使用中时,我发现了我需要的其他东西。

这是我所拥有的表格的简化版本:

+-----+-------------+-----------+
| id  | name       | parent_id |
+-----+------------+-----------+
|  1  | Bob        | 3         |
|  2  | John       | 5         |
|  3  | Larry      | 4         |
|  4  | Kevin      | 0         |
|  5  | Kyle       | 0         |
|  6  | Jason      | 5         |
|  7  | Mildred    | 4         |
|  8  | Mabel      | 6         |
|  9  | Amber      | 4         |
|  10 | Devon      | 5         |
|  11 | Zack       | 0         |
|  12 | Alfred     | 11        |
|  13 | Robert     | 11        |
|  14 | Keith      | 11        |
+----+-------------+-----------+

(自上一个问题以来,我又添加了一些,只是为了有更多示例)现在我希望能够获得父母、孩子和孙子孙女的名单。以下是我发现的查询:

祖父母

SELECT name FROM people WHERE parent_id = 0

儿童

SELECT c.name
FROM people p
JOIN people c ON c.parent_id = p.id
WHERE p.parent_id = 0

还有孙子

SELECT gc.name
FROM people p
JOIN people c ON c.parent_id = p.id
JOIN people gc ON gc.parent_id = c.id
WHERE p.parent_id = 0

我正在为孩子们想办法,所以我暂时先离开其他人。上面针对儿童的查询给出了以下结果:

+---------+
| name    |
+---------+
| John    |
| Larry   |
| Jason   |
| Mildred |
| Amber   |
| Devon   |
| Alfred  |
| Robert  |
| Keith   |
+---------+

这很好,但我需要先按字母顺序排列,首先是父母,然后是孩子。所以我在查询中添加了一个 ORDER BY:

SELECT c.name
FROM people p
JOIN people c ON c.parent_id = p.id
WHERE p.parent_id = 0
ORDER BY p.name, c.name

这给了我:

+---------+
| name    |
+---------+
| Amber   |
| Larry   |
| Mildred |
| Devon   |
| Jason   |
| John    |
| Alfred  |
| Keith   |
| Robert  |
+---------+

很好。但现在的问题是,我也想将父母包括在这个列表中,就在他们孩子所在的位置上方。另外,我想用某种方式来显示结果是父母还是孩子。所以我在考虑另一个名为Rank 的列,它的值可以是1 或2,以表示父母或孩子。所以这就是我想要的结果:

+--------+------+
| name   | rank |
+--------+------+
| Kevin  | 1    |
| Amber  | 2    |
| Larry  | 2    |
| Mildred| 2    |
| Kyle   | 1    |
| Devon  | 2    |
| Jason  | 2    |
| John   | 2    |
| Zack   | 1    |
| Alfred | 2    |
| Keith  | 2    |
| Robert | 2    |
+--------+------+

这有意义吗?我可以使用什么查询来获得该结果?

【问题讨论】:

  • 如果它适合您:在单独的列中显示子项旁边的父项会更容易。您只需添加“p.name as parent”即可获得结果。
  • 您获取祖父母、子女和孙子女的三个查询示例清楚地展示了图结构的复杂性增长速度。出于这个原因,我强烈建议你看看像图数据库这样的技术,比如 neo4j
  • @NorbertvanNobelen 好的,谢谢。这样可行。但我还需要将父母包括在姓名列表中。我怎么能那样做?对于这些项目,在他们的“父母”列下,我可能只是希望它是“NULL”
  • 你可以使用 UNION: SELECT {your children query}, 1 UNION {your parents query}, 2; 1,2 是你的等级,所以这里有多种解决问题的方法:)
  • 在您的最后一个示例中,MableBob 未列出。那是因为他们是孙子吗?

标签: mysql sql


【解决方案1】:

试试这个:

SELECT name, 1 as rank FROM people WHERE parent_id = 0
UNION
SELECT child.name AS name, 2 AS rank
FROM people AS parent, people AS child
WHERE child.parent_id = parent.id AND parent.parent_id = 0 
ORDER BY name;

结果:

+---------+------+
| name    | rank |
+---------+------+
| Jason   |    2 |
| John    |    2 |
| Kevin   |    1 |
| Kyle    |    1 |
| Larry   |    2 |
| Mildred |    2 |
+---------+------+

并添加孙子,rank = 3

SELECT name, 1 as rank FROM people WHERE parent_id = 0
UNION
SELECT child.name AS name, 2 AS rank
FROM people AS parent, people AS child
WHERE child.parent_id = parent.id AND parent.parent_id = 0
UNION
SELECT grandchild.name AS name, 3 AS rank
FROM people AS grandparent, people AS parent, people
AS grandchild WHERE grandchild.parent_id = parent.id
AND parent.parent_id = grandparent.id
ORDER BY rank,name;

结果:

+---------+------+
| name    | rank |
+---------+------+
| Bob     |    3 |
| Jason   |    2 |
| John    |    2 |
| Kevin   |    1 |
| Kyle    |    1 |
| Larry   |    2 |
| Mabel   |    3 |
| Mildred |    2 |
+---------+------+

编辑

现在它已按您的要求排序,但是正如您所见,还有一个附加但最终隐藏的列Family_head

SELECT T.Name, T.Rank FROM (SELECT name, 1 as Rank, Name AS Family_Head FROM people WHERE parent_id = 0
UNION
SELECT child.name AS Name, 2 AS Rank, 
(SELECT p.name FROM people AS p WHERE child.parent_id = p.id) as Family_Head
FROM people AS parent, people AS child
WHERE child.parent_id = parent.id AND parent.parent_id = 0
ORDER BY Family_head, Rank, Name) AS T;

结果:

+---------+------+-------------+
| name    | Rank | Family_Head |
+---------+------+-------------+
| Kevin   |    1 | Kevin       |
| Amber   |    2 | Kevin       |
| Larry   |    2 | Kevin       |
| Mildred |    2 | Kevin       |
| Kyle    |    1 | Kyle        |
| Devon   |    2 | Kyle        |
| Jason   |    2 | Kyle        |
| John    |    2 | Kyle        |
| Zack    |    1 | Zack        |
| Alfred  |    2 | Zack        |
| Keith   |    2 | Zack        |
| Robert  |    2 | Zack        |
+---------+------+-------------+

【讨论】:

  • 不错。这很好。唯一的问题是顺序错误。我需要上面提到的顺序,按字母顺序显示第一个父级,然后按字母顺序显示其所有子级,然后是第二个父级,等等。我尝试添加 ORDER BY parent.name, child.name;但这给出了一个错误
  • @eshellborn 试试ORDER BY rank,name; 它应该会给你想要的输出
  • 那行不通,我需要在我的帖子sqlfiddle.com/#!9/ed315/22
  • @eshellborn 所以你想要一个父母,然后是他的孩子,然后是另一个父母,还有他的孩子,等等?
  • 好的,可以。现在我还需要按 group_id 进行过滤,就像我在上一篇文章 stackoverflow.com/questions/31327393/… 中所做的那样。我不太明白
【解决方案2】:

您正在使用的这种结构很可能在图形数据库或关系数据库中更容易处理,比 MySQL 更好地支持递归查询,但使用 union all 运算符和算术是可能的以达到您正在寻找的结果。

SELECT Generation, Name, Rank 
FROM (

    SELECT 'Grand parent' AS Generation, id*1000 level, name, 1 as rank 
    FROM people WHERE parent_id = 0

    UNION ALL

    SELECT 'Parent', p.id*1000 + 1*100, c.name, 2 as rank
    FROM people p
    JOIN people c ON c.parent_id = p.id
    WHERE p.parent_id = 0

    UNION ALL 

    SELECT 'Grand child', p.id*1000+1*100+gc.id, gc.name, 3 as rank
    FROM people p
    JOIN people c ON c.parent_id = p.id
    JOIN people gc ON gc.parent_id = c.id
    WHERE p.parent_id = 0

) a 
ORDER BY level, name;
-- WHERE Rank <= 2 -- add this or remove the last union to remove grand children

给出如下结果:

|   Generation |     name | rank |
|--------------|----------|------|
| Grand parent | Kevin    |    1 |
|       Parent | Amber    |    2 |
|       Parent | Larry    |    2 |
|       Parent | Mildred  |    2 |
|  Grand child | Bob      |    3 |
| Grand parent | Kyle     |    1 |
|       Parent | Devon    |    2 |
|       Parent | Jason    |    2 |
|       Parent | John     |    2 |
|  Grand child | Mabel    |    3 |
| Grand parent | Zack     |    1 |
|       Parent | Alfred   |    2 |
|       Parent | Keith    |    2 |
|       Parent | Robert   |    2 |

Sample SQL Fiddle

【讨论】:

  • 不可能做出这样的假设。它不必太复杂,我只需要一些方法来区分父母和孩子。重要的是它按照我上面的顺序。我无法更改数据库的结构,因为它内置在我们的 cms 中
  • @eshellborn 好的,让我想一想
  • @eshellborn 现在请看一下。我包括了孙辈,但如果你不想这样做,只需注释掉最后一个联合并查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-23
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 2020-03-21
相关资源
最近更新 更多