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

Usuários ativos semanais para cada dia do log


Para obter uma contagem de "Usuário médio semanal" (pelo meu entendimento de sua especificação... "para cada dia, a contagem de user_ids distintos vistos durante esse dia e nos seis dias anteriores"), uma consulta nos moldes da abaixo poderia ser usado. (A consulta também retorna a contagem de "Usuário médio diário".
SELECT d.day
     , COUNT(DISTINCT u.user_id) AS wau
     , COUNT(DISTINCT IF(u.day=d.day,u.user_id,NULL)) AS dau
  FROM ( SELECT FLOOR(k.ts/86400) AS `day`
           FROM `log` k
          GROUP BY `day`
       ) d
  JOIN ( SELECT FLOOR(l.ts/86400) AS `day`
              , l.user_id
           FROM `log` l
          GROUP BY `day`, l.user_id
       ) u
    ON u.day <= d.day
   AND u.day > d.day - 7
 GROUP BY d.day
 ORDER BY d.day

(Ainda não executei um teste disso; mas farei mais tarde e atualizarei esta declaração se forem necessárias correções.)

Esta consulta está se juntando à lista de usuários de um determinado dia (do u rowsource), para um conjunto de dias da tabela de log (o d fonte de linha). Observe o literal "7" que aparece no predicado de junção (a cláusula ON), que é o que está fazendo a lista de usuários "combinar" com os 6 dias anteriores.

Observe que isso também pode ser estendido para obter a contagem de usuários distintos nos últimos 3 dias, por exemplo, adicionando outra expressão na lista SELECT.
     , COUNT(DISTINCT IF(u.day<=d.day AND u.day>d.day-3,u.user_id,NULL)) AS 3day

Esse literal "7" pode ser aumentado para obter um alcance maior. E esse literal 3 na expressão acima pode ser alterado para obter qualquer número de dias... só precisamos ter certeza de que temos linhas suficientes do dia anterior (de d ) unido a cada linha de u .

NOTA DE DESEMPENHO:Devido às visualizações inline (ou tabelas derivadas, como o MySQL as chama), esta consulta pode não ser muito rápida, pois os conjuntos de resultados para essas visualizações inline devem ser materializados em tabelas MyISAM intermediárias.

A visualização inline com o alias u pode não ser o ideal; pode ser mais rápido juntar-se diretamente à tabela de log. Eu estava pensando em obter uma lista exclusiva de usuários para um determinado dia, que é o que essa consulta na visualização inline me trouxe. Era apenas mais fácil para mim conceituar o que estava acontecendo. E eu estava pensando que se você tivesse centenas do mesmo usuário inserido por dia, a visualização inline eliminaria um monte de duplicatas, antes de fazermos a junção com os outros dias. Uma cláusula WHERE para limitar o número de dias que estão retornando seria melhor adicionado dentro do u e d visualizações em linha. (O d a visualização em linha precisaria incluir um extra de 6 dias anteriores.)

Em outra nota, se a coluna ts for o tipo de dados TIMESTAMP, eu estaria mais inclinado a usar um DATE(ts) expressão para extrair a parte da data. Mas isso retornaria um tipo de dados DATE no conjunto de resultados, em vez de um inteiro, que seria diferente do conjunto de resultados especificado.)
SELECT d.day
     , COUNT(DISTINCT u.user_id) AS wau
     , COUNT(DISTINCT IF(u.day=d.day,u.user_id,NULL)) AS dau
  FROM ( SELECT DATE(k.ts) AS `day`
           FROM `log` k
          GROUP BY `day`
       ) d
  JOIN ( SELECT DATE(l.ts) AS `day`
              , l.user_id
           FROM `log` l
          GROUP BY `day`, l.user_id
       ) u
    ON u.day <= d.day
   AND u.day > DATE_ADD(d.day, INTERVAL -7 DAY)
 GROUP BY d.day
 ORDER BY d.day