sql >> Database >  >> RDS >> Mysql

Wekelijks actieve gebruikers voor elke dag uit log

Om een ​​"Wekelijkse gemiddelde gebruiker" telling te krijgen (volgens mijn begrip van uw specificatie... "voor elke dag, het aantal verschillende gebruikers-ID's gezien tijdens die dag en de voorgaande zes dagen"), een query in de trant van die hieronder kan gebruikt worden. (De zoekopdracht retourneert ook het aantal "Dagelijkse gemiddelde gebruiker".

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

(Ik heb dit nog niet getest, maar dat zal ik later doen, en ik zal deze verklaring bijwerken als er correcties nodig zijn.)

Deze zoekopdracht wordt toegevoegd aan de lijst met gebruikers voor een bepaalde dag (van de u rowsource), naar een reeks dagen uit de logtabel (de d rijbron). Let op de letterlijke "7" die verschijnt in het join-predikaat (de ON-clausule), waardoor de gebruikerslijst wordt "gematcht" met de voorgaande 6 dagen.

Merk op dat dit ook kan worden uitgebreid om het aantal verschillende gebruikers van de afgelopen 3 dagen te krijgen, bijvoorbeeld door een andere uitdrukking toe te voegen aan de SELECT-lijst.

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

Die letterlijke "7" zou kunnen worden verhoogd om een ​​groter bereik te krijgen. En die letterlijke 3 in de bovenstaande uitdrukking kan worden gewijzigd om een ​​willekeurig aantal dagen te krijgen ... we moeten er alleen zeker van zijn dat we genoeg rijen van de vorige dag hebben (van d ) toegevoegd aan elke rij van u .

PRESTATIEOPMERKING:vanwege de inline-weergaven (of afgeleide tabellen, zoals MySQL ze noemt), is deze query mogelijk niet erg snel, omdat de resultatensets voor die inline-weergaven moeten worden omgezet in tussenliggende MyISAM-tabellen.

De inline-weergave met een alias als u is mogelijk niet optimaal; het is misschien sneller om rechtstreeks naar de logtabel te gaan. Ik dacht aan het krijgen van een unieke lijst met gebruikers voor een bepaalde dag, en dat is wat die zoekopdracht in de inline-weergave me opleverde. Het was gewoon makkelijker voor mij om te begrijpen wat er aan de hand was. En ik dacht dat als je honderden dezelfde gebruiker voor de dag had ingevoerd, de inline-weergave een hele reeks duplicaten zou verwijderen, voordat we de andere dagen samenvoegden. Een WHERE-clausule om het aantal dagen te beperken dat we die terugkeren, kunnen het beste worden toegevoegd in de u en d inline-weergaven. (De d inline-weergave zou een extra eerdere 6 dagen moeten bevatten.)

Nog een opmerking, als de ts-kolom het TIMESTAMP-gegevenstype is, zou ik meer geneigd zijn om een ​​DATE(ts) te gebruiken expressie om het datumgedeelte te extraheren. Maar dat zou een DATE-gegevenstype in de resultatenset teruggeven, in plaats van een geheel getal, dat anders zou zijn dan de door u opgegeven resultaten.)

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. MS Access:voor- en nadelen

  2. Hoe sla ik een waarde van een SQL-query op in een variabele?

  3. Laravel-querybuilder - Hoe te groeperen op alias of onbewerkte groupBy te doen?

  4. mysqldump test vergrendelingstabellen