你如何编写一个MySQL查询来限制连接表的结果(如果效果更好,则选择子选项)并计算连接表中的项目数?
例如,假设您有三个表:项目,任务和注释,项目有0个或更多任务,任务有0个或更多注释。如何将每个项目返回的任务数量限制为3,并返回每个项目的任务总数和每个任务的注释?
这是我想象的结果集:
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'等仅表示项目的标题,'Task1','Task2'等代表任务的标题。
最终,(在解析查询结果之后)我希望能够显示如下内容:
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)
我猜这必须用子选择完成(这很好),但我似乎无法弄清楚如何使用连接完成这个并且我没有足够好的处理sub选择做这样的事情。
答案 0 :(得分: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_tasks
和num_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
因为我认为你想要最近的项目。
答案 1 :(得分: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
}
}