将子级别添加到SQL结果中

时间:2015-07-09 22:24:37

标签: mysql sql

这是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    |
+--------+------+

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

2 个答案:

答案 0 :(得分: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        |
+---------+------+-------------+

答案 1 :(得分:1)

您正在使用的结构类型很可能更容易在图形数据库或关系数据库中处理,并且比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