Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como posso criar uma tabela de análise de coorte semanal usando o mysql?


Esta consulta é modificada da que escrevi aqui:Análise de coorte em SQL

Aqui está a 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

Então, o cerne disso é pegar os usuários e a data em que eles se inscreveram e formatar a data pelo número da semana do ano, já que estamos fazendo uma coorte semanal.
SELECT
  UserId,
  DATE_FORMAT(AddedDate, "%Y-%u") AS cohort
FROM users

Como queremos agrupar por coorte, temos que colocar isso em uma subconsulta na parte FROM da consulta.

Então queremos juntar as informações de pagamento dos usuários.
SELECT DISTINCT
  payments.UserId,
  FLOOR(DATEDIFF(payments.PaymentDate, users.AddedDate)/7) AS Offset
  FROM payments
  LEFT JOIN users ON (users.UserId = payments.UserId)

Isso obterá eventos de pagamento semanais exclusivos por usuário pelo número de semanas em que eles são usuários. Usamos distintos porque se um usuário fez duas compras em uma semana, não queremos contar como dois usuários.

Não usamos apenas a tabela de pagamentos, pois alguns usuários podem se cadastrar e não receber pagamentos. Então, selecionamos na tabela de usuários e juntamos na tabela de pagamentos.

Você então agrupa por semana - u.cohort. Em seguida, você agrega os números das semanas para descobrir quantas pessoas efetuaram pagamentos nas semanas após a inscrição.

A versão do mysql que usei tinha sql_mode definido como only_full_group_by. Então, para obter o tamanho da coorte, coloquei a maior parte da consulta na subconsulta para que eu pudesse juntar os usuários para obter o tamanho da coorte.

Considerações adicionais:

Filtrar por semanas é simples. tb.cohort> data inicial e tb.cohort
Você pode considerar o uso de uma tabela de calendário para cobrir os casos em que não há inscrições de usuários durante a semana.

Aqui está um violino com tudo funcionando:http://sqlfiddle.com/#!9/172dbe/ 1