2010-01-29 87 views
1

你将如何编写一个MySQL查询来限制连接表的结果(或者如果这样做效果更好,则选择子选择)并计算连接表或表中的项数?例如,假设您有三个表格:项目,任务和评论,其中项目有0个或更多任务,任务有0个或更多注释。您如何将每个项目返回的任务数量限制为3,并返回每个项目的任务总数和每个任务的评论数?如何编写一个MySQL查询来限制一个或多个连接表的结果,并计算连接表或多个表中的项的数量?

这就是我想象中的结果集的样子:

project_id, project_title, task_id, task_title, num_tasks, num_comments 
------------------------------------------------------------------------ 
1, Project1, 1, Task1, 4, 3 
1, Project1, 2, Task2, 4, 0 
1, Project1, 3, Task3, 4, 9 
2, Project2, 10, Task10, 20, 0 
2, Project2, 11, Task11, 20, 0 
2, Project2, 12, Task12, 20, 2 
3, Project3, 20, Task20, 17, 5 
3, Project3, 21, Task21, 17, 1 
3, Project3, 22, Task22, 17, 2 

其中“PROJECT1”,“Project2的”等只是代表一个项目的标题和“任务1”,“任务2”等代表任务的标题。

最后,(通过查询的结果分析后)我想能够显示这样的事情:

Project1 (4 tasks) 
    Task1 (3 comments) 
    Task2 (0 comments) 
    Task3 (9 comments) 
Project2 (20 tasks) 
    Task10 (0 comments) 
    Task11 (0 comments) 
    Task12 (2 comments) 
Project3 (17 tasks) 
    Task20 (5 comments) 
    Task21 (1 comments) 
    Task22 (2 comments) 

我猜这必须与子选择做(这是好的),但我似乎无法弄清楚如何使用连接完成此操作,并且我没有足够的处理子选择来执行此类操作。

+0

*您如何限制每个项目返回的任务数3 *:你准备好哪三个?例如,当你'ORDER BY task_id ASC'或'ORDER BY num_comments DESC'时,前三名? – BalusC 2010-01-29 00:46:57

回答

0

老实说,我会在多个查询中这样做,以避免相关的子查询。

但在这里你去:

SELECT p.project_id, p.project_title, 
    t1.task_id, t1.task_title, 
    (SELECT COUNT(*) FROM tasks t 
     WHERE t.project_id = p.project_id) AS num_tasks, 
    COALESCE((SELECT COUNT(*) FROM comments c 
     WHERE c.task_id = t1.task_id), 0) AS num_comments 
FROM projects p 
JOIN tasks t1 ON (p.project_id = t1.project_id) 
LEFT OUTER JOIN tasks t2 
    ON (p.project_id = t2.project_id AND t1.task_id > t2.task_id) 
GROUP BY t1.task_id 
HAVING COUNT(*) < 3; 

考虑,像上述(num_tasksnum_comments相关子查询必须执行多次 - 一次的t1每一行。

您可以单独运行这些查询,并在应用程序代码的结果结合得到的结果:

SELECT p.project_id, p.project_title, 
    t1.task_id, t1.task_title 
FROM projects p 
JOIN tasks t1 ON (p.project_id = t1.project_id) 
LEFT OUTER JOIN tasks t2 
    ON (p.project_id = t2.project_id AND t1.task_id > t2.task_id) 
GROUP BY t1.task_id 
HAVING COUNT(*) < 3; 

SELECT task_id, COUNT(*) AS num_comments 
FROM comments 
WHERE task_id IN (...list of task_id values from first query...) 
GROUP BY task_id; 

SELECT project_id, COUNT(*) AS num_tasks 
FROM tasks 
GROUP BY project_id; 

即使运行三个独立的查询,这样可能会更快的整体比跑步更复杂的查询得到所有结果在一起。我说可能,因为它取决于我们正在讨论的数据量。可以肯定的是,你必须使用你自己的数据库来测试两个解决方案。


重新您的后续问题,我应该这样做在一个子查询:

SELECT p.project_id, p.project_title, 
    t1.task_id, t1.task_title 
FROM (SELECT * FROM projects ORDER BY last_updated DESC LIMIT 5) p 
. . . 

请注意,这不是一个相关子查询; RDBMS只需要执行一次子查询。

我用DESC,因为我假设你想要最近的项目。

+0

因此,在这种情况下,将查询拆分为多个查询然后使用脚本语言(PHP等)处理单独的结果集会更有效率?相关的子查询是通常应该避免的事情吗? – 2010-01-29 19:28:02

+0

这很有道理,但我还有一个问题,我打算将其包含在我的原始问题中。在第一个查询中(三个查询的集合),您将如何限制返回的项目总数。在目前的形式下,对于所有项目它最多返回三个任务,但是假设我想将其限制为不超过5个,由项目字段last_updated排序?顺便说一下,非常感谢您的帮助。 – 2010-01-31 02:43:07

+0

这实际上是我尝试过的同样的事情,但显然我坚持使用的MySQL(5.0.45)版本不支持子查询中的LIMIT。 – 2010-02-04 05:16:27

0

我会说你不得不使用多个查询和循环这样的事情。
有可能是一种方式,但它超出了我:)
下面是一些suedo代码来显示如何我完成这个时间

select project_id, project_title from projects 
select project_id, count(*) As num_tasks from tasks group by project_id 
select task_id, count(*) As num_comment from comments group by task_id 

foreach (int projectId in projects.Rows) 
{ 
    select task_id, task_title from tasks where project_id = projectID limit 3 
    foreach (int taskID in tasks.Rows) 
    { 
     select comment_id, comment from comments limit 3 
    } 
} 
相关问题