Esta consulta está modificada de la que escribí aquí:Análisis de cohortes en SQL
Aquí está la consulta final:
SELECT
STR_TO_DATE(CONCAT(tb.cohort, ' Monday'), '%X-%V %W') as date,
size,
w1,
w2,
w3,
w4,
w5,
w6,
w7
FROM (
SELECT u.cohort,
IFNULL(SUM(s.Offset = 0), 0) w1,
IFNULL(SUM(s.Offset = 1), 0) w2,
IFNULL(SUM(s.Offset = 2), 0) w3,
IFNULL(SUM(s.Offset = 3), 0) w4,
IFNULL(SUM(s.Offset = 4), 0) w5,
IFNULL(SUM(s.Offset = 5), 0) w6,
IFNULL(SUM(s.Offset = 6), 0) w7
FROM (
SELECT
UserId,
DATE_FORMAT(AddedDate, "%Y-%u") AS cohort
FROM users
) as u
LEFT JOIN (
SELECT DISTINCT
payments.UserId,
FLOOR(DATEDIFF(payments.PaymentDate, users.AddedDate)/7) AS Offset
FROM payments
LEFT JOIN users ON (users.UserId = payments.UserId)
) as s ON s.UserId = u.UserId
GROUP BY u.cohort
) as tb
LEFT JOIN (
SELECT DATE_FORMAT(AddedDate, "%Y-%u") dt, COUNT(*) size FROM users GROUP BY dt
) size ON tb.cohort = size.dt
Entonces, el núcleo de esto es que capturamos a los usuarios y la fecha en que se registraron y formateamos la fecha por número de año-semana, ya que estamos haciendo una cohorte semanal.
SELECT
UserId,
DATE_FORMAT(AddedDate, "%Y-%u") AS cohort
FROM users
Como queremos agrupar por cohorte, tenemos que poner esto en una subconsulta en la parte DESDE de la consulta.
Entonces queremos unir la información de pago de los usuarios.
SELECT DISTINCT
payments.UserId,
FLOOR(DATEDIFF(payments.PaymentDate, users.AddedDate)/7) AS Offset
FROM payments
LEFT JOIN users ON (users.UserId = payments.UserId)
Esto obtendrá eventos de pago semanales únicos por usuario por la cantidad de semanas que han sido usuarios. Usamos distinto porque si un usuario hizo 2 compras en una semana, no queremos contar eso como dos usuarios.
No solo usamos la tabla de pagos, porque algunos usuarios pueden registrarse y no tener pagos. Así que seleccionamos de la tabla de usuarios y nos unimos a la tabla de pagos.
Luego agrupa por semana - u.cohort. Luego agrega los números de la semana para averiguar cuántas personas hicieron pagos las semanas posteriores a su registro.
La versión de mysql que utilicé tenía sql_mode establecido en only_full_group_by. Entonces, para obtener el tamaño de la cohorte, puse la mayor parte de la consulta en la subconsulta para poder unirme a los usuarios para obtener el tamaño de la cohorte.
Otras consideraciones:
Filtrar por semanas es sencillo. tb.cohort> fecha de inicio y tb.cohort
Es posible que desee considerar el uso de una tabla de calendario para cubrir los casos en los que no hay registros de usuarios durante la semana.
Aquí hay un violín con todo funcionando:http://sqlfiddle.com/#!9/172dbe/ 1