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

Ugentlige aktive brugere for hver dag fra log

For at få et "Ugentligt gennemsnitligt antal brugere" (ifølge min forståelse af din specifikation... "for hver dag, antallet af distinkte user_id'er set i løbet af den dag og de foregående seks dage"), en forespørgsel på linje med nedenstående kunne bruges. (Forespørgslen returnerer også antallet af "Dagligt gennemsnitsbruger".

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

(Jeg har endnu ikke kørt en test af dette, men det vil jeg senere, og jeg vil opdatere denne erklæring, hvis der er behov for rettelser.)

Denne forespørgsel slutter sig til listen over brugere for en given dag (fra u rowsource), til et sæt dage fra logtabellen (d rowsource). Bemærk det bogstavelige "7", der vises i join-prædikatet (ON-klausulen), det er det, der får brugerlisten "matchet" til de foregående 6 dage.

Bemærk, at dette også kan udvides for at få det distinkte brugerantal over de seneste 3 dage, for eksempel ved at tilføje et andet udtryk i SELECT-listen.

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

Det bogstavelige "7" kunne øges for at få en større rækkevidde. Og den bogstavelige 3 i udtrykket ovenfor kunne ændres for at få et hvilket som helst antal dage... vi skal bare være sikre på, at vi har nok rækker fra tidligere dage (fra d ) sluttet til hver række fra u .

BEMÆRK OM YDELSE:På grund af de inline-visninger (eller afledte tabeller, som MySQL kalder dem), er denne forespørgsel muligvis ikke særlig hurtig, da resultatsættene for disse inline-visninger skal materialiseres til mellemliggende MyISAM-tabeller.

Den indbyggede visning kaldet u er måske ikke optimalt; det kan være hurtigere at slutte sig direkte til log-tabellen. Jeg tænkte på at få en unik liste over brugere for en given dag, hvilket er, hvad den forespørgsel i inline-visningen fik mig til. Det var bare nemmere for mig at begrebsliggøre, hvad der foregik. Og jeg tænkte på, at hvis du havde flere hundrede af den samme bruger indtastet for dagen, ville den indbyggede visning luge en hel masse af dubletterne ud, før vi sluttede til de andre dage. En WHERE-klausul for at begrænse antallet af dage, vi vender tilbage ville bedst føjes til u og d inline visninger. (d inline-visning skal inkludere en ekstra tidligere 6 dage.)

En anden bemærkning, hvis ts kolonne er TIMESTAMP datatype, ville jeg være mere tilbøjelig til at bruge en DATE(ts) udtryk for at udtrække datodelen. Men det ville returnere en DATE-datatype i resultatsættet i stedet for et heltal, som ville være forskelligt fra det resultatsæt, du har angivet.)

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. 6 måder at tilføje en måned til en dato i MariaDB

  2. MySQL fejl 1005?

  3. MySQL Left Joins:Vælg alt fra én tabel, men kun matchende værdi i anden tabel med kriterier

  4. AWS RDS backup metoder