sql >> Databasteknik >  >> RDS >> Mysql

Veckovisa aktiva användare för varje dag från loggen

För att få ett "Veckomedelvärde för användare" (enligt jag förstår din specifikation... "för varje dag, antalet distinkta användare_id som setts under den dagen och de föregående sex dagarna"), en fråga i linje med den nedan kan användas. (Frågan returnerar också antalet "Dagligt genomsnittlig användare".

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

(Jag har ännu inte kört ett test av detta, men jag kommer att göra det senare, och jag kommer att uppdatera detta uttalande om några korrigeringar behövs.)

Den här frågan går med i listan över användare för en viss dag (från u rowsource), till en uppsättning dagar från loggtabellen (d radkälla). Notera den bokstavliga "7" som visas i join-predikatet (ON-satsen), det är det som får användarlistan att "matcha" till de föregående 6 dagarna.

Observera att detta också kan utökas för att få det distinkta antalet användare under de senaste 3 dagarna, till exempel genom att lägga till ytterligare ett uttryck i SELECT-listan.

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

Den där bokstavliga "7" skulle kunna ökas för att få ett större utbud. Och den bokstavliga 3:an i uttrycket ovan kan ändras för att få valfritt antal dagar... vi behöver bara vara säkra på att vi har tillräckligt många rader för föregående dag (från d ) kopplade till varje rad från u .

PRESTANDANMÄRKNING:På grund av de inbäddade vyerna (eller härledda tabeller, som MySQL kallar dem), kanske den här frågan inte är särskilt snabb, eftersom resultatuppsättningarna för dessa inbäddade vyer måste materialiseras till mellanliggande MyISAM-tabeller.

Den infogade vyn alias som u kanske inte är optimalt; det kan vara snabbare att ansluta direkt till loggtabellen. Jag tänkte på att få en unik lista över användare för en viss dag, vilket är vad den frågan i inlinevyn fick mig. Det var bara lättare för mig att föreställa mig vad som pågick. Och jag tänkte att om du hade angett hundratals av samma användare för dagen, skulle den inbyggda vyn sålla bort en hel massa av dubbletterna, innan vi gick med i de andra dagarna. En WHERE-klausul för att begränsa antalet dagar vi återvänder skulle bäst läggas till i u och d inline-vyer. (d inline-vyn skulle behöva inkludera ytterligare 6 dagar tidigare.)

Å andra sidan, om ts-kolumnen är TIMESTAMP-datatyp, skulle jag vara mer benägen att använda en DATE(ts) uttryck för att extrahera datumdelen. Men det skulle returnera en DATE-datatyp i resultatuppsättningen, snarare än ett heltal, som skulle skilja sig från resultatuppsättningen du angav.)

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


  1. De använda SELECT-satserna har ett annat antal kolumner

  2. Ansluta IBM DB2 med IRI Software

  3. Jämför datum i T-SQL, ignorera tidsdelen

  4. ClassCastException:java.math.BigInteger kan inte castas till java.lang.Long på att ansluta till MySQL