Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wöchentlich aktive Benutzer für jeden Tag aus dem Protokoll

Um die Anzahl der "wöchentlichen durchschnittlichen Benutzer" zu erhalten (nach meinem Verständnis Ihrer Spezifikation ... "für jeden Tag die Anzahl der unterschiedlichen user_ids, die an diesem Tag und in den vorangegangenen sechs Tagen gesehen wurden"), eine Abfrage in Anlehnung an die untenstehende könnte verwendet werden. (Die Abfrage gibt auch die Anzahl der "täglichen durchschnittlichen Benutzer" zurück.

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

(Ich habe dies noch nicht getestet, aber ich werde es später tun und diese Erklärung aktualisieren, falls Korrekturen erforderlich sind.)

Diese Abfrage fügt sich in die Liste der Benutzer für einen bestimmten Tag ein (aus dem u rowsource) in eine Reihe von Tagen aus der Protokolltabelle (die d Zeilenquelle). Beachten Sie die wörtliche „7“, die im Join-Prädikat (die ON-Klausel) erscheint. Dadurch wird die Benutzerliste mit den letzten 6 Tagen „abgeglichen“.

Beachten Sie, dass dies auch erweitert werden könnte, um die eindeutige Benutzeranzahl der letzten 3 Tage zu erhalten, indem Sie beispielsweise einen weiteren Ausdruck in der SELECT-Liste hinzufügen.

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

Diese wörtliche "7" könnte erhöht werden, um einen größeren Bereich zu erhalten. Und dieses Literal 3 im obigen Ausdruck könnte geändert werden, um eine beliebige Anzahl von Tagen zu erhalten ... wir müssen nur sicherstellen, dass wir genügend Vortagszeilen haben (von d ) mit jeder Zeile von u verbunden .

LEISTUNGSHINWEIS:Aufgrund der Inline-Ansichten (oder abgeleiteten Tabellen, wie MySQL sie nennt) ist diese Abfrage möglicherweise nicht sehr schnell, da die Ergebnismengen für diese Inline-Ansichten in MyISAM-Zwischentabellen materialisiert werden müssen.

Die Inline-Ansicht mit dem Alias ​​u möglicherweise nicht optimal; es könnte schneller sein, direkt der Protokolltabelle beizutreten. Ich dachte daran, eine eindeutige Liste von Benutzern für einen bestimmten Tag zu erhalten, was mir diese Abfrage in der Inline-Ansicht gebracht hat. Es war einfach einfacher für mich, mir vorzustellen, was vor sich ging. Und ich dachte, wenn Sie Hunderte desselben Benutzers für einen Tag eingegeben hätten, würde die Inline-Ansicht eine ganze Reihe von Duplikaten aussortieren, bevor wir die Verknüpfung mit den anderen Tagen vornehmen. Eine WHERE-Klausel, um die Anzahl der Tage zu begrenzen, an denen wir zurückgeben, werden am besten innerhalb des u hinzugefügt und d Inline-Ansichten. (Das d Die Inline-Ansicht müsste zusätzliche frühere 6 Tage enthalten.)

Wenn die ts-Spalte vom Datentyp TIMESTAMP ist, würde ich eher dazu neigen, ein DATE(ts) zu verwenden Ausdruck, um den Datumsteil zu extrahieren. Aber das würde einen DATE-Datentyp in der Ergebnismenge zurückgeben, statt einer Ganzzahl, die sich von der von Ihnen angegebenen Ergebnismenge unterscheiden würde.)

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