Mysql
 sql >> Database >  >> RDS >> Mysql

Utenti attivi settimanali per ogni giorno da log

Per ottenere un conteggio "Utente medio settimanale" (secondo la mia comprensione delle tue specifiche... "per ogni giorno, il conteggio di user_id distinti visti durante quel giorno e nei sei giorni precedenti"), una query sulla falsariga di quella seguente potrebbe essere usato. (La query restituisce anche il conteggio "Utente medio giornaliero".

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

(Non ho ancora eseguito un test di questo; ma lo farò in seguito e aggiornerò questa dichiarazione se saranno necessarie correzioni.)

Questa query si unisce all'elenco di utenti per un determinato giorno (da u rowsource), a un insieme di giorni dalla tabella di log (il d origine riga). Nota il letterale "7" che appare nel predicato di join (la clausola ON), ecco cosa fa "abbinare" l'elenco utenti ai 6 giorni precedenti.

Tieni presente che questo potrebbe anche essere esteso per ottenere il conteggio degli utenti distinti negli ultimi 3 giorni, ad esempio aggiungendo un'altra espressione nell'elenco SELECT.

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

Quel letterale "7" potrebbe essere aumentato per ottenere una gamma più ampia. E quel 3 letterale nell'espressione sopra potrebbe essere modificato per ottenere un numero qualsiasi di giorni... dobbiamo solo essere sicuri di avere abbastanza righe del giorno precedente (da d ) unito a ciascuna riga da u .

NOTA SULLE PRESTAZIONI:a causa delle viste inline (o delle tabelle derivate, come le chiama MySQL), questa query potrebbe non essere molto veloce, poiché i set di risultati per quelle viste inline devono essere materializzati in tabelle MyISAM intermedie.

La vista in linea alias come u potrebbe non essere ottimale; potrebbe essere più veloce unire direttamente alla tabella di registro. Stavo pensando in termini di ottenere un elenco univoco di utenti per un determinato giorno, che è ciò che mi ha procurato quella query nella visualizzazione in linea. È stato solo più facile per me concettualizzare cosa stava succedendo. E stavo pensando che se avessimo inserito centinaia dello stesso utente per un giorno, la visualizzazione in linea eliminerebbe un sacco di duplicati, prima che facessimo l'unione agli altri giorni. Una clausola WHERE per limitare il numero di giorni in cui stanno tornando sarebbe meglio aggiungere all'interno di u e d viste in linea. (Il d la visualizzazione in linea dovrebbe includere altri 6 giorni precedenti.)

In un'altra nota, se la colonna ts è il tipo di dati TIMESTAMP, sarei più propenso a utilizzare un DATE(ts) espressione per estrarre la parte della data. Ma ciò restituirebbe un tipo di dati DATE nel set di risultati, anziché un numero intero, che sarebbe diverso dal set di risultati specificato.)

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