Zademonstruję taki pomysł w oparciu o to, co jest dla mnie najbardziej sensowne i sposób, w jaki odpowiedziałbym, gdyby pytanie zostało przedstawione tak samo jak tutaj:
Najpierw załóżmy, że zestaw danych jako taki, nazwiemy tabelę 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 |
| ... | ... |
+---------+---------------------+
Mogą istnieć inne kolumny, ale nam to nie przeszkadza.
Przede wszystkim powinniśmy określić granice tego tygodnia, w tym celu możemy użyć ADDDATE()
. W połączeniu z ideą, że dzisiejsza data-dzisiejszy dzień tygodnia (metoda DAYOFWEEK()
w MySQL ) to niedziela.
Na przykład:jeśli dzisiaj jest środa 10, Wed - 3 = Sun
, zatem 10 - 3 = 7
i możemy spodziewać się, że niedziela będzie siódmą.
Możemy uzyskać WeekStart
i WeekEnd
znaczniki czasu w ten sposób:
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;
Uwaga:w PostgreSQL istnieje DATE_TRUNC()
funkcja, która zwraca początek określonej jednostki czasu, podając datę, taką jak początek tygodnia, miesiąc, godzina itd. Ale to nie jest dostępne w MySQL.
Następnie wykorzystajmy WeekStart i WeekEnd w celu wyselekcjonowania naszego zestawu danych, w tym przykładzie pokażę tylko, jak filtrować, używając na stałe zakodowanych dat:
SELECT *
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'
Powinno to zwrócić nasz zestaw danych w postaci wycinków z tylko istotnymi wynikami:
+---------+---------------------+
| user_id | login_timestamp |
+---------+---------------------+
| 2 | 2015-09-29 14:05:08 |
| 1 | 2015-09-29 14:05:12 |
+---------+---------------------+
Możemy wtedy zredukować nasz zestaw wyników tylko do user_id
si odfiltrować duplikaty. następnie policz w ten sposób:
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
odfiltruje duplikaty, a licznik zwróci tylko kwotę.
W połączeniu otrzymujemy:
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")
Zastąp CURDATE()
z dowolnym znacznikiem czasu, aby uzyskać liczbę zalogowanych użytkowników w tym tygodniu.
Ale muszę to rozłożyć na kilka dni, słyszę jak płaczesz. Oczywiście! a oto jak:
Najpierw przetłumaczmy nasze nadmiernie informacyjne znaczniki czasu na same dane daty. Dodajemy DISTINCT
ponieważ nie przeszkadza nam, że ten sam użytkownik loguje się dwa razy tego samego dnia. liczymy użytkowników, a nie loginy, prawda? (zauważ, że cofamy się tutaj):
SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d")
FROM `logins`
To daje:
+---------+-----------------+
| user_id | login_timestamp |
+---------+-----------------+
| 1 | 2015-09-29 |
| 2 | 2015-09-29 |
| 4 | 2015-09-22 |
| ... | ... |
+---------+-----------------+
To zapytanie zawiniemy w sekundę, aby policzyć pojawienie się każdej daty:
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`
Używamy licznika i grupowania, aby uzyskać listę według daty, która zwraca:
+-----------------+-------+
| login_timestamp | count |
+-----------------+-------+
| 2015-09-29 | 1 +
| 2015-09-22 | 2 +
+-----------------+-------+
A po całej ciężkiej pracy obie połączone:
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`;
Daje ci dzienny podział logowań na dzień w tym tygodniu. Ponownie zastąp CURDATE()
aby uzyskać inny tydzień.
Jeśli chodzi o samych użytkowników, którzy się zalogowali, połączmy te same rzeczy w innej kolejności:
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
Mam dwa wewnętrzne zapytania, pierwsze to logins
:
SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
FROM `logins`
Dostarczy listę użytkowników i dni, w których się logowali, bez duplikatów.
Następnie mamy logincounts
:
SELECT `user_id`, COUNT(*) AS `login_count`
FROM `logins` -- See previous subquery.
GROUP BY `user_id`) `logincounts`
Zwróci tę samą listę z liczbą logowań każdego użytkownika.
I na koniec:WYBIERZ user_id
Z logincounts
-- Zobacz poprzednie podzapytanie.GDZIE login_count
> 6
Filtrowanie tych, którzy nie zalogowali się 7 razy, i upuszczanie kolumny daty.
Trochę to trwało długo, ale myślę, że jest pełne pomysłów i myślę, że na pewno może pomóc w ciekawym udzieleniu odpowiedzi podczas rozmowy kwalifikacyjnej. :)