MySQL嵌套选择:我可以使用外部选择的任何数据吗?

时间:2014-12-16 18:46:47

标签: mysql sql select nested-query

假设我有下表users

id name
1  John
2  Mike
3  Max

posts

id author_id date       title
1  1         2014-12-12 Post 2
2  1         2014-12-10 Post 1
3  2         2014-10-01 Lorem ipsum
...and so on

我想要一个包含以下数据的查询:

  • 用户名

  • 上周内用户的帖子数量

  • 上个月内用户的帖子数量

我只能为每个用户(以下示例中的ID为1)执行此操作:

SELECT
  `name`,
  (SELECT COUNT(*) FROM `posts`
   WHERE
     `author` = 1 AND
     UNIX_TIMESTAMP()-UNIX_TIMESTAMP(`date`) < 7*24*3600) AS `posts7`,
  (SELECT COUNT(*) FROM `posts`
   WHERE
     `author` = 1 AND
     UNIX_TIMESTAMP()-UNIX_TIMESTAMP(`date`) < 30*24*3600) AS `posts30`
FROM `users`
WHERE `id` = 1

我怀疑MySQL允许在一个查询中为所有用户执行此操作,如果我可以在内部和外部SELECT之间交换数据。我可能使用错误的词语,但我真的希望这里的人能理解我的需求,我会得到一些帮助。

3 个答案:

答案 0 :(得分:1)

这不是最终的SQL,但会给你一个jist ......

Select name, sum(case when datewithin7 then 1 else 0 end) as posts7, 
             sum(case when datewithin30 then 1 else 0 end) as posts30
from name
left join posts on name.id = posts.nameid
GROUP BY name.

注意你需要分组。但是我没有时间将案例陈述放在一起......

答案 1 :(得分:1)

尝试这样的事情

  SELECT
    `name`,
    sum(IF(`date` between DATE(NOW()-INTERVAL 7 DAY) and now() , 1, 0) as posts7,
    sum(IF(`date` between DATE(NOW()-INTERVAL 30 DAY) and now() , 1, 0) as posts30
  FROM
    `users` as u, posts as p
  WHERE
    u.id = p.author_id
  GROUP BY
    1

答案 2 :(得分:1)

当然,聚合非嵌套查询是解决问题的方法,尽管Benni和xQbert都编写了无限查询 - 这些查询在满足目标的同时非常低效。考虑(根据Benni的回答改编):

SELECT `name`
, SUM(IF(
   `date` between DATE(NOW()-INTERVAL 7 DAY) and now() 
   , 1
   , 0) as posts7
, SUM(IF(
   p.author_id IS NULL 
   , 0
   , 1) as posts30
FROM `users` as u
LEFT JOIN posts as p
ON u.id = p.author_id
AND p.date > NOW()-INTERVAL 30 DAY
GROUP BY name

请注意,不使用转换为UNIX时间戳允许数据库使用索引(如果可用)来解析查询。

但是,有些情况下使用嵌套查询更有效/更合适。因此,虽然它不是问题的最佳解决方案:

SELECT
`name`
, (SELECT COUNT(*) 
   FROM `posts` AS p7
   WHERE p7.author = users.id 
   AND p7.`date` > NOW() - INTERVAL 7 DAY) AS `posts7`
, (SELECT COUNT(*) 
   FROM `posts` AS p30
   WHERE p30.author = users.id 
   AND p30.`date` > NOW() - INTERVAL 30 DAY) AS `posts30`
FROM `users` 
WHERE `id` = 1