2014-12-16 1 views
0

Давайте представим, у меня есть следующая таблица users:MySQL вложенной выбор: могу ли я использовать любые данные из внешнего выбора?

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 

И я хотел бы иметь запрос, содержащий следующие данные:

  • пользователя наименование

  • количество сообщений пользователя в течение последней недели

  • количество сообщений пользователя в течение последнего месяца

Я могу сделать это только для каждого отдельного пользователя (с идентификатором 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. Я, вероятно, использую неправильные слова, но я действительно надеюсь, что люди здесь поймут мои потребности, и я помогу.

+1

Почему бы не использовать соединение между должностями и имени и два заявления случая, чтобы определить, если пост <7 дней или менее чем за 30 дней, то совокупный результат. .. – xQbert

ответ

1

Это не окончательный SQL, но дает тэк ...

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

попробовать что-то вроде этого

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 
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 
Смежные вопросы