SQL查询只选择孙子

时间:2015-07-09 20:17:22

标签: mysql sql

我对SQL很陌生,试图绕过它,但它有点令人困惑。这是我正在使用的简化版本。

我有一个名为people的表:

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

上表是人员列表。他们的parent_id列指的是他们的父母是谁。如果桌面上没有父母,则他们的parent_id为0.

现在,我希望能够获得每组人员的单独名单:祖父母,子女和孙子女。

很容易找到祖父母(拉里和凯文),我可以这样查询:

SELECT name FROM people WHERE parent_id = 0

但是当谈到让孩子(John,Larry,Jason和Mildred)和孙子(Bob和Mabel)时,我迷失了。

在英语中,这将是获取孩子的过程:“从表中获取所有结果。对于每一个,查看他们的父ID。在表中找到具有该ID的结果。参见< em>那个人的 id,如果是0,那么原来的人就是孩子。将它们添加到我们将要显示的内容列表中。“

对于孙子女来说,它将与上述相同,但只是增加了一步。

这有意义吗?如何将上述过程编写为SQL查询?

5 个答案:

答案 0 :(得分:7)

这可以使用简单的JOIN来解决。

选择子项列表:

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

答案 1 :(得分:2)

首先,非常重要的是要知道这个问题很容易回答,如果你知道你正在与固定的几代人一起工作(例如,对孙子孙女来说)。如果这个表最终会有很多代,并且你想(例如)通过整个族树找到所有Kyle的后代,那么你不会用一个查询来完成它。 (我有一个处理任意级别的树世代的存储过程。)所以现在,让我们找到祖父母/孙子。

正如你所说,找到祖父母很容易......

mysql> select name from people where parent_id = 0;
+-------+
| name  |
+-------+
| Kevin |
| Kyle  |
+-------+
2 rows in set (0.00 sec)

现在,找到孩子也不错。

让我们找到凯尔的孩子们:

mysql> select p1.name from people p1 where p1.parent_id in 
           (select p2.id from people p2 where p2.name = 'Kyle');             
+-------+
| name  |
+-------+
| John  |
| Jason |
+-------+
2 rows in set (0.02 sec)

这是凯尔的孙子们:

mysql> select p3.name from people p3 where p3.parent_id in
           (select p2.id from people p2 where p2.parent_id in
              (select p3.id from people p3 where p3.name = 'Kyle'));
+-------+
| name  |
+-------+
| Mabel |
+-------+
1 row in set (0.01 sec)

mysql> 

走向另一个方向......谁是梅布尔的父母?

mysql> select p1.name from people p1 where p1.id = 
           (select p2.parent_id from people p2 where p2.name = 'Mabel');  
+-------+
| name  |
+-------+
| Jason |
+-------+
1 row in set (0.00 sec)

mysql> 

......和她的祖父母:

mysql> select p1.name from people p1 where p1.id = 
           (select p2.parent_id from people p2 where p2.id = 
               (select p3.parent_id from people p3 where p3.name = 'Mabel'));
+------+
| name |
+------+
| Kyle |
+------+
1 row in set (0.00 sec)

如果你需要曾祖父母/曾孙子,你可以看到我所遵循的模式来进行这些查询。但是,如果您需要更多代,则生成的查询将变得难以处理,并且循环的存储过程将按顺序排列。

Oracle数据库有一个更优雅的解决方案,一个名为“CONNECT BY PRIOR”的SQL扩展。有关更多阅读(以及MySQL存储过程示例),请在StackOverflow上查看Connect By Prior Equivalent for MySQL

最后一点:如果你还没有,请帮自己一个忙,并且:

mysql> create index ix_parent_id on people(parent_id);
Query OK, 0 rows affected (0.06 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> 

它将显着提高这类查询的性能。

答案 2 :(得分:0)

要获得孙子,请尝试此查询。

SELECT name FROM people WHERE parent_id IN (SELECT id from people where parent_id >0);

答案 3 :(得分:0)

如果您使用查询设计器,那将更容易理解。我正在为SQL Server的视图设计者拍照。我希望它可以提供帮助。

这是你找到孩子的方法:

enter image description here

我建议你为parent_id字段允许null并使用null而不是0,这样你就可以建立从id(作为pk)到parent_id(作为fk)的关系。这将使使用设计师时更容易。

如果您还需要一个寻找孙子的例子,请告诉我。

答案 4 :(得分:0)

这没有JOIN语句,但作为SQL学习者,我发现它更容易:

  1. 对于孙子:

    SELECT parent.name as Parent, child.name AS Child 
    FROM people AS parent, people AS child 
    WHERE child.parent_id = parent.id AND parent.parent_id = 0;
    
  2. 对于孩子们:

    SELECT parent.name as Parent, child.name AS Child 
    FROM people AS parent, people AS child 
    WHERE child.parent_id = parent.id;
    
  3. 对于所有儿童 - 父母对:

    {{1}}
  4. 我花了一段时间,但很有趣:D