Я пытаюсь сделать кумулятивный агрегат в 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 строки для перебора (пользователей * пользователей). Есть ли лучшая практика в том, как это сделать?
заблаговременно.
Вы хотите "искусственно создать" даты начала и окончания для присоединения либо во временной таблице, либо непосредственно в строке.
Предположим, вы хотели, чтобы каждая комбинация начала, конца месяца, а затем внутри этого интервала времени разбивалась по источникам и подсчитывалась, как вы описали. Вы можете сделать это:
выберите 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' соединения в соответствии с вашими потребностями.
Любопытно, есть ли у кого-то лучшее решение.