Как посчитать агрегаты по дате в MySQL

0

Я пытаюсь сделать кумулятивный агрегат в MySQL.

Мои исходные данные выглядят следующим образом: (мои даты - месяц/день/год)

user_id    created_at    source
1          1/1/01        foo
2          1/1/01        foo
3          1/2/01        bar
4          1/2/01        foo
5          1/3/01        foo
     ....

Учитывая это, я хотел бы сделать результат, который выглядит следующим образом:

date    source    total_in_source
1/1/01  foo       2
1/2/01  foo       3
1/3/01  foo       4

где total_in_source - это совокупность количества пользователей, созданных_а между первым и текущим значением даты.

Я могу сделать это, используя коррелированный подзапрос, но это немного неэффективно:

select 
date(user.created_at) d,
user.source as user_source,
(select count(*) from users u where u.source = user_source and month(u.created_at) <= month_joined) as total_users_source,
from users user group by d, user_source

Я немного огляделся, и кажется, что это может быть шагом в правильном направлении:

select date(u1.created_at) as 'd',
u1.source as 'source', 
count(distinct u2.id) as count_users
from users u1, users u2
where
u2.created_at BETWEEN DATE(u1.created_at) AND DATE_ADD(DATE(u1.created_at), interval 1 day) and
group by d, source

но даже это самосоединение и производит n ^ 2 строки для перебора (пользователей * пользователей). Есть ли лучшая практика в том, как это сделать?

заблаговременно.

Теги:

1 ответ

1
Лучший ответ

Вы хотите "искусственно создать" даты начала и окончания для присоединения либо во временной таблице, либо непосредственно в строке.

Предположим, вы хотели, чтобы каждая комбинация начала, конца месяца, а затем внутри этого интервала времени разбивалась по источникам и подсчитывалась, как вы описали. Вы можете сделать это:

выберите u.source, sdates.val start, edates.val end, count (*) from (выберите distinct (date (created_at)) val от пользователей, где day (created_at) = 1) sdates join (выберите выделение (date (created_at)) val от пользователей, где day (created_at) = 1) edates присоединяются к пользователям u на u.created_at между sdates.val и edates.val группой по sdates.val, edates.val, u.source;

В основном внутренние запросы "дадут вам даты", а внешний - фактически вычисляет. Может быть полезно иметь таблицу "дат", в которой есть одна строка для каждой релевантной даты для вашего проекта, поэтому вы можете легко присоединиться к ней и не делать этого вуду, но в отсутствие этого, похоже, это работает.

Кроме того, вам может не понадобиться каждая комбинация начала и конца, поэтому вы можете играть с условиями "where" во внутренних запросах или 'on' соединения в соответствии с вашими потребностями.

Любопытно, есть ли у кого-то лучшее решение.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню