Ich werde eine solche Idee demonstrieren, basierend auf dem, was für mich am sinnvollsten ist und wie ich antworten würde, wenn die Frage so gestellt würde wie hier:
Nehmen wir zunächst einen Datensatz als solchen an, wir nennen die Tabelle logins
:
+---------+---------------------+
| user_id | login_timestamp |
+---------+---------------------+
| 1 | 2015-09-29 14:05:05 |
| 2 | 2015-09-29 14:05:08 |
| 1 | 2015-09-29 14:05:12 |
| 4 | 2015-09-22 14:05:18 |
| ... | ... |
+---------+---------------------+
Es kann noch andere Spalten geben, aber die stören uns nicht.
Zuerst sollten wir die Grenzen dieser Woche bestimmen, dazu können wir ADDDATE()
verwenden . Kombiniert mit der Idee, dass das heutige Datum der heutige Wochentag ist (MySQLs DAYOFWEEK()
), ist das Datum von Sonntag.
Zum Beispiel:Wenn heute Mittwoch der 10. ist, Wed - 3 = Sun
, also 10 - 3 = 7
, und wir können damit rechnen, dass Sonntag der 7. ist.
Wir können WeekStart
erhalten und WeekEnd
Zeitstempel auf diese Weise:
SELECT
DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1-DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00") WeekStart,
DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7-DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59") WeekEnd;
Hinweis:In PostgreSQL gibt es ein DATE_TRUNC()
Funktion, die den Beginn einer bestimmten Zeiteinheit bei einem gegebenen Datum zurückgibt, z. B. Wochenbeginn, Monat, Stunde usw. Aber das ist in MySQL nicht verfügbar.
Als Nächstes verwenden wir WeekStart und weekEnd, um auf unseren Datensatz zu klicken. In diesem Beispiel zeige ich nur, wie man mit fest codierten Daten filtert:
SELECT *
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'
Dies sollte unseren Datensatz aufgeteilt zurückgeben, mit nur relevanten Ergebnissen:
+---------+---------------------+
| user_id | login_timestamp |
+---------+---------------------+
| 2 | 2015-09-29 14:05:08 |
| 1 | 2015-09-29 14:05:12 |
+---------+---------------------+
Wir können dann unsere Ergebnismenge auf nur die user_id
reduzieren s und filtern Duplikate heraus. dann zählen, so:
SELECT COUNT(DISTINCT user_id)
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'
DISTINCT
filtert Duplikate heraus und count gibt nur die Anzahl zurück.
Zusammen ergibt dies:
SELECT COUNT(DISTINCT user_id)
FROM `logins`
WHERE login_timestamp
BETWEEN DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00")
AND DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59")
Ersetzen Sie CURDATE()
mit einem beliebigen Zeitstempel, um die Anzahl der Benutzeranmeldungen dieser Woche zu erhalten.
Aber ich muss das auf Tage herunterbrechen, ich höre dich weinen. Na sicher! und so geht's:
Lassen Sie uns zunächst unsere überinformativen Zeitstempel nur in die Datumsdaten übersetzen. Wir fügen DISTINCT
hinzu weil es uns nichts ausmacht, dass sich derselbe Benutzer zweimal am selben Tag anmeldet. Wir zählen Benutzer, keine Anmeldungen, richtig? (beachten Sie, dass wir hier zurücktreten):
SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d")
FROM `logins`
Dies ergibt:
+---------+-----------------+
| user_id | login_timestamp |
+---------+-----------------+
| 1 | 2015-09-29 |
| 2 | 2015-09-29 |
| 4 | 2015-09-22 |
| ... | ... |
+---------+-----------------+
Diese Abfrage werden wir mit einer zweiten umschließen, um das Auftreten jedes Datums zu zählen:
SELECT `login_timestamp`, count(*) AS 'count'
FROM (SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d") AS `login_timestamp` FROM `logins`) `loginsMod`
GROUP BY `login_timestamp`
Wir verwenden count und eine Gruppierung, um die Liste nach Datum zu erhalten, die zurückgibt:
+-----------------+-------+
| login_timestamp | count |
+-----------------+-------+
| 2015-09-29 | 1 +
| 2015-09-22 | 2 +
+-----------------+-------+
Und nach all der harten Arbeit, beides zusammen:
SELECT `login_timestamp`, COUNT(*)
FROM (
SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d") AS `login_timestamp`
FROM `logins`
WHERE login_timestamp BETWEEN DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 1- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 00:00:00") AND DATE_FORMAT(ADDDATE(CURDATE(), INTERVAL 7- DAYOFWEEK(CURDATE()) DAY), "%Y-%m-%d 23:59:59")) `loginsMod`
GROUP BY `login_timestamp`;
Gibt Ihnen in dieser Woche eine tägliche Aufschlüsselung der Anmeldungen pro Tag. Ersetzen Sie wieder CURDATE()
um eine andere Woche zu bekommen.
Was die Benutzer selbst betrifft, die sich angemeldet haben, kombinieren wir dieselben Dinge in einer anderen Reihenfolge:
SELECT `user_id`
FROM (
SELECT `user_id`, COUNT(*) AS `login_count`
FROM (
SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
FROM `logins`) `logins`
GROUP BY `user_id`) `logincounts`
WHERE `login_count` > 6
Ich habe zwei innere Abfragen, die erste ist logins
:
SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
FROM `logins`
Liefert die Liste der Benutzer und die Tage, an denen sie sich angemeldet haben, ohne Duplikate.
Dann haben wir logincounts
:
SELECT `user_id`, COUNT(*) AS `login_count`
FROM `logins` -- See previous subquery.
GROUP BY `user_id`) `logincounts`
Gibt dieselbe Liste zurück, mit einer Zählung, wie viele Anmeldungen jeder Benutzer hatte.
Und zuletzt:user_id
AUSWÄHLEN FROM logincounts
-- Siehe vorherige Unterabfrage.WHERE login_count
> 6
Filtern Sie diejenigen heraus, die sich 7 Mal nicht angemeldet haben, und löschen Sie die Datumsspalte.
Das ist etwas lang geworden, aber ich denke, es steckt voller Ideen und ich denke, es kann definitiv helfen, in einem Arbeitsinterview auf interessante Weise zu antworten. :)