Я видел много вопросов, связанных с подсчетом данных с разными диапазонами дат, но в отдельных запросах. Мне необходимо отобразить, сколько раз каждый пользователь заходил сегодня, вчера и сколько раз пользователь запрашивал «Раздел файлов». Поэтому мне нужно отобразить много столбцов, каждый с разным количеством для каждого пользователя в разных диапазонах дат или с указанием c деталей.
Вот сценарии для создания и вставки исходных данных:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(45) DEFAULT NULL,
`realname` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `username_UNIQUE` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `history` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(45) DEFAULT NULL,
`access_date` datetime DEFAULT NULL,
`detail` varchar(45) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO users (username,realname) VALUES
("mwazowski","Mike Wazowski"),("jsullivan","James P. Sullivan"),
("rboggs","Randall Boggs"),("hwaternoose","Henry J. Waternoose");
INSERT INTO history (username,access_date,detail) VALUES
("","2020-04-22 12:00:00","publicData"),
("mwazowski","2020-04-22 12:01:00","login"),
("mwazowski","2020-04-22 12:02:00","practice"),
("mwazowski","2020-04-22 12:04:00","files"),
("mwazowski","2020-04-22 12:10:00","logout"),
("","2020-04-23 12:25:00","publicData"),
("","2020-04-23 12:27:00","publicData"),
("jsullivan","2020-04-23 12:30:00","login"),
("jsullivan","2020-04-23 12:35:00","files"),
("jsullivan","2020-04-23 12:40:00","logout"),
("","2020-04-23 12:52:00","publicData"),
("rboggs","2020-04-23 13:00:00","login"),
("rboggs","2020-04-23 13:01:00","files"),
("rboggs","2020-04-23 13:40:00","logout"),
("","2020-04-23 13:43:00","publicData");
Это набор результатов для таблицы Пользователи :
+----+-------------+---------------------+
| id | username | realname |
+----+-------------+---------------------+
| 1 | mwazowski | Mike Wazowski |
| 2 | jsullivan | James P. Sullivan |
| 3 | rboggs | Randall Boggs |
| 4 | hwaternoose | Henry J. Waternoose |
| | | |
+----+-------------+---------------------+
И это набор результатов для таблицы История :
+----+-----------+---------------------+------------+
| id | username | access_date | detail |
+----+-----------+---------------------+------------+
| 1 | | 2020-04-22 12:00:00 | publicData |
| 2 | mwazowski | 2020-04-22 12:01:00 | login |
| 3 | mwazowski | 2020-04-22 12:02:00 | practice |
| 4 | mwazowski | 2020-04-22 12:04:00 | files |
| 5 | mwazowski | 2020-04-22 12:10:00 | logout |
| 6 | | 2020-04-23 12:25:00 | publicData |
| 7 | | 2020-04-23 12:27:00 | publicData |
| 8 | jsullivan | 2020-04-23 12:30:00 | login |
| 9 | jsullivan | 2020-04-23 12:35:00 | files |
| 10 | jsullivan | 2020-04-23 12:40:00 | logout |
| 11 | | 2020-04-23 12:52:00 | publicData |
| 12 | rboggs | 2020-04-23 13:00:00 | login |
| 13 | rboggs | 2020-04-23 13:01:00 | files |
| 14 | rboggs | 2020-04-23 13:40:00 | logout |
| 15 | | 2020-04-23 13:43:00 | publicData |
+----+-----------+---------------------+------------+
Вот запрос, который я разработал, который отображает подсчеты по группам записей доступа по пользователям, диапазонам дат на сегодня и вчера и задает c подробные данные (записи добавляются с полем detail = 'files'):
select coalesce(u.realname,"PUBLIC") username,
coalesce(h2.todayCount,0) nToday,
coalesce(h3.yesterdayCount,0) nYesterday,
coalesce(h4.fileCount,0) nFiles
from (select distinct username from history) h1
left join users u on h1.username=u.username
left join (select username,count(1) todayCount from history
where access_date>=current_date() group by username) h2
on h1.username=h2.username
left join (select username,count(1) yesterdayCount from history
where access_date between (current_date()-1) and current_date() group by username) h3
on h1.username=h3.username
left join (select username,count(1) fileCount from history
where detail="files" group by username) h4
on h1.username=h4.username order by h1.username;
Этот запрос работает и отображает данные по мере необходимости, но он становится медленнее, поскольку существует больше данных, а также мне может понадобиться добавить больше столбцов позже, что потребует дополнительного чтения всей истории. Таблица истории читается несколько раз, и если потребуется больше диапазонов дат, она станет хуже. Это результат запроса с начальными данными:
+-------------------+--------+------------+--------+
| username | nToday | nYesterday | nFiles |
+-------------------+--------+------------+--------+
| PUBLIC | 4 | 1 | 0 |
| James P. Sullivan | 3 | 0 | 1 |
| Mike Wazowski | 0 | 4 | 1 |
| Randall Boggs | 3 | 0 | 1 |
+-------------------+--------+------------+--------+
Даты, включенные в пример данных, дают ожидаемый результат только тогда, когда сегодня 23 апреля. Чтобы эти тестовые данные работали в любой будущий день, запустите следующие сценарии:
UPDATE history SET access_date=concat((curdate() - INTERVAL 1 DAY)," ",time(access_date)) WHERE id<=5;
UPDATE history SET access_date=concat(curdate()," ",time(access_date)) WHERE id>5;