Ще демонстрирам такава идея въз основа на това, което има най-голям смисъл за мен и начина, по който бих отговорил, ако въпросът беше представен по същия начин като тук:
Първо, нека приемем набор от данни като такъв, ще назовем таблицата 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 |
| ... | ... |
+---------+---------------------+
Може да има и други колони, но ние нямаме нищо против тях.
Първо трябва да определим границите на тази седмица, за това можем да използваме ADDDATE()
. В комбинация с идеята, че днешната дата-днешният ден от седмицата (DAYOFWEEK()
на MySQL ), е датата неделя.
Например:Ако днес е сряда, 10-ти, Wed - 3 = Sun
, следователно 10 - 3 = 7
и можем да очакваме неделя да бъде 7-ми.
Можем да получим WeekStart
и WeekEnd
времеви отпечатъци по този начин:
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;
Забележка:в PostgreSQL има DATE_TRUNC()
функция, която връща началото на определена времева единица, дадена дата, като начало на седмица, месец, час и т.н. Но това не е налично в MySQL.
След това нека използваме WeekStart и weekEnd, за да разделим нашия набор от данни, в този пример просто ще покажа как да филтрирам, използвайки твърдо кодирани дати:
SELECT *
FROM `logins`
WHERE login_timestamp BETWEEN '2015-09-29 14:05:07' AND '2015-09-29 14:05:13'
Това трябва да върне нашия набор от данни нарязан, само с подходящи резултати:
+---------+---------------------+
| user_id | login_timestamp |
+---------+---------------------+
| 2 | 2015-09-29 14:05:08 |
| 1 | 2015-09-29 14:05:12 |
+---------+---------------------+
След това можем да намалим набора от резултати само до user_id
s и филтрирайте дубликати. след това пребройте по този начин:
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
ще филтрира дубликатите и count ще върне само сумата.
Комбинирано това става:
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")
Заменете CURDATE()
с произволно времево клеймо, за да получите броя на потребителските влизания за тази седмица.
Но трябва да разделя това на дни, чувам те да плачеш. Разбира се! и ето как:
Първо, нека преведем нашите прекалено информативни времеви отпечатъци само в данните за датата. Добавяме DISTINCT
защото нямаме нищо против един и същи потребител да влезе два пъти в един и същи ден. ние броим потребители, а не влизания, нали? (обърнете внимание, че се отдръпваме тук):
SELECT DISTINCT user_id, DATE_FORMAT(login_timestamp, "%Y-%m-%d")
FROM `logins`
Това дава:
+---------+-----------------+
| user_id | login_timestamp |
+---------+-----------------+
| 1 | 2015-09-29 |
| 2 | 2015-09-29 |
| 4 | 2015-09-22 |
| ... | ... |
+---------+-----------------+
Тази заявка ще завършим с втора, за да преброим появяванията на всяка дата:
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`
Използваме брой и групиране, за да получим списъка по дата, което връща:
+-----------------+-------+
| login_timestamp | count |
+-----------------+-------+
| 2015-09-29 | 1 +
| 2015-09-22 | 2 +
+-----------------+-------+
И след цялата упорита работа, и двете заедно:
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`;
Ще ви даде дневна разбивка на влизанията на ден през тази седмица. Отново заменете CURDATE()
за да получите различна седмица.
Що се отнася до самите потребители, които са влезли, нека комбинираме същите неща в различен ред:
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
Имам две вътрешни заявки, първата е logins
:
SELECT DISTINCT `user_id`, DATE_FORMAT(`login_timestamp`, "%Y-%m-%d")
FROM `logins`
Ще предостави списъка с потребители и дните, в които са влезли, без дубликати.
След това имаме logincounts
:
SELECT `user_id`, COUNT(*) AS `login_count`
FROM `logins` -- See previous subquery.
GROUP BY `user_id`) `logincounts`
Ще върне същия списък, с брой влизания на всеки потребител.
И накрая:ИЗБЕРЕТЕ user_id
ОТ logincounts
-- Вижте предишната подзаявка. WHERE login_count
> 6
Филтриране на онези, които не са влезли 7 пъти, и премахване на колоната с дата.
Това доста стана дълго, но мисля, че е пълно с идеи и мисля, че определено може да помогне да се отговори по интересен начин на работно интервю. :)