sql >> Base de Datos >  >> RDS >> Mysql

Usuarios activos semanales para cada día desde el registro

Para obtener un recuento de "Usuario promedio semanal" (según mi comprensión de su especificación ... "para cada día, el recuento de ID de usuario distintos vistos durante ese día y los seis días anteriores"), una consulta similar a la siguiente puede ser usado. (La consulta también devuelve el recuento de "Usuario promedio diario".

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

(Todavía no he realizado una prueba de esto, pero lo haré más tarde y actualizaré esta declaración si se necesitan correcciones).

Esta consulta se une a la lista de usuarios para un día determinado (desde el u rowsource), a un conjunto de días de la tabla de registro (el d fuente de fila). Tenga en cuenta el literal "7" que aparece en el predicado de unión (la cláusula ON), eso es lo que hace que la lista de usuarios "coincida" con los 6 días anteriores.

Tenga en cuenta que esto también podría extenderse para obtener el recuento de usuarios distintos durante los últimos 3 días, por ejemplo, agregando otra expresión en la lista SELECT.

     , COUNT(DISTINCT IF(u.day<=d.day AND u.day>d.day-3,u.user_id,NULL)) AS 3day

Ese "7" literal podría aumentarse para obtener un rango mayor. Y ese literal 3 en la expresión anterior podría cambiarse para obtener cualquier cantidad de días... solo debemos asegurarnos de que tenemos suficientes filas de días anteriores (de d ) unido a cada fila desde u .

NOTA DE RENDIMIENTO:debido a las vistas en línea (o tablas derivadas, como las llama MySQL), esta consulta puede no ser muy rápida, ya que los conjuntos de resultados para esas vistas en línea deben materializarse en tablas MyISAM intermedias.

La vista en línea con alias como u puede no ser óptimo; podría ser más rápido unirse directamente a la tabla de registro. Estaba pensando en términos de obtener una lista única de usuarios para un día determinado, que es lo que me dio esa consulta en la vista en línea. Era más fácil para mí conceptualizar lo que estaba pasando. Y estaba pensando que si tuviera cientos del mismo usuario ingresado por día, la vista en línea eliminaría un montón de duplicados, antes de unirnos a los otros días. Una cláusula WHERE para limitar la cantidad de días que están regresando sería mejor agregarlo dentro de la u y d vistas en línea. (La d la vista en línea debería incluir 6 días anteriores adicionales).

En otra nota, si la columna ts es el tipo de datos TIMESTAMP, estaría más inclinado a usar un DATE(ts) expresión para extraer la parte de la fecha. Pero eso devolvería un tipo de datos DATE en el conjunto de resultados, en lugar de un número entero, que sería diferente del conjunto de resultados que especificó).

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