Выбрать запрос внутри запроса? - PullRequest
2 голосов
/ 14 октября 2011

Итак, я хочу сравнить новых пользователей с возвращающимися пользователями в таблице по месяцам. У меня есть таблица, которая содержит каждое действие с именем пользователя и отметкой даты.

Я могу легко вытащить пользователей, которые выполнили действие, например, в январе 2011 года. Чтобы увидеть, является ли каждый пользователь новым, мне нужно запустить его имя пользователя для всех предыдущих записей (до января 2011 года).

В своих вознях я придумал следующее:

  SELECT ini.username,
         MIN(ini.datetime) AS firstAction,
         COUNT(ini.datetime) AS numMonth,
         (SELECT COUNT(*) 
            FROM tableActions tot
           WHERE tot.username = ini.username
             AND tot.datetime < '201101%' 
             AND tot.datetime > '201001%') AS numTotal
    FROM tableActions ini
   WHERE DATETIME >= '201101%' 
     AND DATETIME < '201102%'
GROUP BY ini.username
ORDER BY firstAction

Это не ошибка, но и не заканчивается. Кажется, довольно интенсивно.

Ответы [ 4 ]

5 голосов
/ 14 октября 2011

Вы можете переписать запрос следующим образом (при условии, что tableactions.datetime имеет тип данных DATETIME):

   SELECT ini.username,
          MIN(ini.datetime) AS firstAction,
          COUNT(ini.datetime) AS numMonth,
          x.numTotal
     FROM tableActions ini
LEFT JOIN (SELECT tot.username,
                  COUNT(*) AS numTotal
             FROM tableActions tot
            WHERE tot.datetime > '2010-01-01'
              AND tot.datetime < '2011-01-01'
         GROUP BY tot.username) x ON x.username = ini.username
    WHERE ini.datetime BETWEEN '2011-01-01' AND '2011-01-31'
 GROUP BY ini.username
 ORDER BY firstAction

Может помочь иметь индекс как минимум на username, хотя стоит рассмотреть индекс покрытия с использованием username, datetime.

Сравнение datetime выглядит подозрительно - LIKE единственный, кто поддерживает символы подстановки.

1 голос
/ 14 октября 2011

Я думаю, что простого соединения таблица к себе с подходящим предложением where будет достаточно (этот запрос прямо из моей головы, не проверенный):

SELECT    curr_activity.username, COUNT(prev_activity.username) AS did_something_in_the_past
FROM      tableActions AS curr_activity
LEFT JOIN tableActions AS prev_activity ON curr_activity.username = prev_activity.username 
WHERE     curr_activity.datetime >= '2011-01-01' AND curr_activity.datetime < '2011-02-01'
AND       prev_activity.datetime <  '2011-01-01' 
GROUP BY  curr_activity.username

Индексы имеют значение.Вы должны индексировать столбцы username и datetime, а столбец datetime должен иметь тип данных datetime или аналогичный.

0 голосов
/ 14 октября 2011

Я думаю, что вы можете заменить

SELECT COUNT(*) 
        FROM tableActions tot
       WHERE tot.username = ini.username
         AND tot.datetime < '201101%' 
         AND tot.datetime > '201001%'

на

SELECT 1
        FROM tableActions tot
       WHERE tot.username = ini.username
         AND tot.datetime < '201101%' 
         AND tot.datetime > '201001%' LIMIT 1

, поэтому он не должен циклически просматривать все записи и считать их.

0 голосов
/ 14 октября 2011
SELECT username,
MIN(datetime) AS firstAction,
MAX(datetime) AS numMonth,
COUNT(*) AS numTotal
GROUP BY ini.username
HAVING numTotal > 1 
WHERE DATETIME between '201001%' AND '201102%'
ORDER BY username
* I think this collapsed version is what you need ?  
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...