在mySQL中从所有父母中选择所有孩子

时间:2010-06-30 21:25:11

标签: php sql mysql

我有一个这样的简单表:

+------------+---------+-----------+--------------+
| comment_id | post_id | parent_id | comment_text |
+------------+---------+-----------+--------------+
|          1 |     200 |         0 |          a   |
|          2 |     200 |         0 |          b   |
|          3 |     200 |         1 |          c   |
|          4 |     200 |         1 |          d   |
|          5 |     200 |         0 |          e   |
|          6 |     200 |         2 |          f   |
|          7 |     200 |         2 |          g   |
|          8 |     200 |         0 |          h   |
|          9 |     200 |         0 |          i   |
|         10 |     200 |         1 |          k   |
+------------+---------+-----------+--------------+
  • 列parent_id告诉我们此评论是对具有此ID的其他评论的回复。

  • 假设只有一个级别的评论嵌套。

现在我需要返回仅前5个父评论以及属于他们的所有子项。

我有一个查询,但有一个问题。

    (
     SELECT c.* 
     FROM comments AS c 
     WHERE c.post_id = '200' AND parent_id='0'
     LIMIT 0,5
    )
    UNION 
    (
     SELECT c.*
     FROM comments AS c
     WHERE c.post_id = '200' AND c.parent_id IN 
     (
      SELECT c.comment_id
      FROM comments AS c 
      WHERE c.post_id= '200' AND parent_id='0'
      LIMIT 0,5
     )
    )

问题是我当前的mySQL版本在子查询中不支持LIMIT。 似乎我两次执行相同的SELECT查询!

我确信必须有办法更优雅地做到这一点。

5 个答案:

答案 0 :(得分:1)

最后我最终使用的东西就像Andomar建议的那样,但没有子查询:

        (
        select  *
        from    comments c
        where   c.post_id = '200' 
                and c.parent_id = 0
        order by comment_id DESC limit 0, 4
        )
union
       (
        select  *
        from    comments c
        join    comments p
        on      c.parent_id = p.comment_id
        where   c.post_id = '200' 
                and c.parent_id != '0'
        )
        order by comment_id DESC

编辑:正如niaher正确指出的那样,此查询返回的结果集大于所需的结果集。这使得这个解决方案出错了。

幸运的是,我找到了另一种方法,更优雅,更清洁。

正确的方法:

SELECT c.*
    FROM (
        SELECT comment_id
        FROM comments
        WHERE post_id = 200 AND parent_id = 0
        ORDER BY comment_id ASC
        LIMIT 0,5       
    ) AS q
JOIN comments AS c
    ON c.comment_id = q.comment_id OR c.parent_id = q.comment_id

我已经测试了这个查询,它的运行速度比前一个快。

答案 1 :(得分:1)

这是最优雅的方式:http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/。您将遇到的一个问题是,插入需要一些时间,因为其他行需要更新;然而,这可以通过一些创造力来避免。那篇文章是一个很好的开始。

答案 2 :(得分:0)

你能做2次选择吗?

Select * from comments where parentID = 0 limit 5

select * from comments where parentID IN (*list of the 5 parentIDs)

答案 3 :(得分:0)

在我的MySQL版本中,您可以在子查询中使用限制:

select  *
from    (
        select  *
        from    comments c
        where   c.post_id = '200' 
                and c.parent_id = 0
        limit    0, 3
        ) s
union
select  c.*
from    (
        select  *
        from    comments c
        where   c.post_id = '200' 
                and c.parent_id = 0
        limit    0, 3
        ) p
join    comments c
on      c.parent_id = p.comment_id;

如果没有MySQL不支持的with语句,重复选择很难避免。您可以创建一个临时表来存储它们:

drop table if exists top5comments;

create table top5comments
    select  *
    from    comments c
    where   c.post_id = '200' 
            and c.parent_id = 0
    limit    0, 3;

insert  top5comments
select  children.*
from    top5comments parents
join    comments children
on      children.parent_id = parents.comment_id;

select * from top5comments;

如果查询可以同时由多个连接运行,则需要修改。

P.S。顺便说一下,limit语句通常伴随着order by子句。如果没有order by,您将获得任意行,结果可能因查询而异。

答案 4 :(得分:0)

也许你的意思是:

SELECT
  *,
  (CASE WHEN parent_id = 0 THEN comment_id ELSE parent_id END) AS use_id
FROM
  comments
WHERE
  (CASE WHEN parent_id = 0 THEN comment_id ELSE parent_id END) IN (
    SELECT    comment_id
    FROM      comments
    WHERE     parent_id = 0
    ORDER BY  comment_id ASC
    LIMIT     3)
ORDER BY
  use_id ASC,
  parent_id;

它的作用是取三个'first'(由comment_id ASC排序)父评论及其所有孩子,然后按父母/ comment_id排序整个列表(父母先是,后面的孩子)。

那么那么结束是为了SQLite(这就是我测试这些东西的方式)。

- 编辑

如果存在这些记录(超过10个记录):

comment_id  post_id  parent_id  comment
1           200      0          a
2           200      0  b
3           200      1  c
4           200      1  d
5           200      0  e
6           200      2  f
7           200      2  g
8           200      0  h
9           200      0  i
10          200      1  j
11          200      1  k
12          200      2  l
13          200      0  m
14          200      1  n

这将是结果:

comment_id  post_id parent_id   comment use_id
1        200    0   a   1
3        200    1   c   1
4        200    1   d   1
10       200    1   j   1
11       200    1   k   1
14       200    1   n   1
2        200    0   b   2
6        200    2   f   2
7        200    2   g   2
12       200    2   l   2
5        200    0   e   5