Я пытаюсь создать SQL-запрос для следующих результатов:
id, name, Users in group, Messages in groups, Message type 1 in groups, Message type 2 in groups
1 Group1 4 3 2 1
2 Group2 3 2 1 1
3 Group1 1 1 1 0
Моя база данных:
create database user_test;
use user_test;
CREATE TABLE `user` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`group_id` BIGINT NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `user_group` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(100)
CHARACTER SET utf8
COLLATE utf8_bin NOT NULL,
UNIQUE KEY `unique` (`name`) USING BTREE,
PRIMARY KEY (`id`)
);
CREATE TABLE `message` (
`id` BIGINT NOT NULL AUTO_INCREMENT,
`user_id` BIGINT NOT NULL,
`type` INT NOT NULL,
`date` DATETIME NOT NULL,
UNIQUE KEY `unique` (`user_id`, `type`, `date`) USING BTREE,
PRIMARY KEY (`id`)
);
ALTER TABLE user
ADD CONSTRAINT user_group_c_fk FOREIGN KEY (group_id) REFERENCES user_group(id);
ALTER TABLE message
ADD CONSTRAINT user_a_fk FOREIGN KEY (user_id) REFERENCES user(id);
И начальное значение:
INSERT INTO `user_group`
VALUES (1, "Group 1"),
(2, "Group 2"),
(3, "Group 3");
INSERT INTO `user`
VALUES (1, "User 1", 1),
(2, "User 2", 1),
(3, "User 3", 1),
(4, "User 4", 1),
(5, "User 5", 2),
(6, "User 6", 2),
(7, "User 7", 2),
(8, "User 8", 3);
INSERT INTO `message`
VALUES (1, 1, 1, "2019-07-25 00:00:00"),
(2, 1, 2, "2019-07-25 00:00:01"),
(3, 1, 2, "2019-07-25 00:00:02"),
(4, 5, 1, "2019-07-25 00:00:03"),
(5, 6, 2, "2019-07-25 00:00:04"),
(6, 8, 1, "2019-07-25 00:00:05");
Мне интересно, возможны ли результаты. Я пытаюсь с чем-то вроде этого:
use user_test;
select user_group.id,
user_group.name,
count(user.id) As "Users in group",
count(message.id) AS "Messages in groups",
count(message.type = 1) AS "Message type1 in groups",
count(message.type = 2) AS "Message type2 in groups"
FROM user_group
LEFT JOIN user ON user.group_id = user_group.id
LEFT JOIN message ON message.user_id = user.id
WHERE user_group.id = message.user_id
GROUP BY user_group.id;
Но, конечно, это совершенно неправильный запрос. Я думаю, что база данных конфигурации не поможет в этой ситуации, но она разделена на всю систему, которую я не могу изменить. Я хотел бы создать этот один общий запрос для конечной точки бэкэнда - лучшим решением будет один запрос для всех результатов.
О, правда. Я не могу удалить это предложение WHERE... Но проблема все та же.
Серьезно рассмотрите возможность решения проблем с отображением данных в коде приложения, если таковые имеются.
Но первый шаг — проверить, могу ли я сгенерировать этот результат в базе данных.
@RaymondNijland, возможно, немного неясно, но обратите внимание, что я сказал предложение в WHERE, а не предложение а WHERE.
да, я заметил это после того, как написал свой комментарий и удалил свой комментарий до того, как вы разместили свой комментарий @jarlh
Я думаю, в таблице сообщений есть только 2 типа: один и два. Тогда 4-й столбец в результате будет суммой 5-го и 6-го. Я прав?
Сообщения в группах = сообщение тип1 + сообщение тип2, да, там всего два типа сообщения.






Я очень близок к тому, чтобы получить надлежащий результат! Но все же не правильный, но, может быть, поможет...
use user_test;
select user_group.id,
user_group.name,
count(user.id) As "Users in group",
count(message.id) AS "Messages in groups",
count(CASE message.type WHEN 1 THEN 1 ELSE null end) AS "Message type1 in groups",
count(CASE message.type WHEN 2 THEN 1 ELSE null end) AS "Message type2 in groups" FROM user_group LEFT JOIN user ON
user.group_id = user_group.id LEFT JOIN message ON message.user_id =
user.id WHERE user_group.id = user.group_id GROUP BY user_group.id,
message.type
Надеюсь это поможет. Я делаю Inner Join вместо левого соединения. Вы можете измениться, если это необходимо.
select
ug.id,
ug.name,
count(u.id) as users_in_group,
count(m.id) as messages_in_group,
count(decode(m.type,'1',count(m.id))) as message_type1_in_group,
count(decode(m.type,'2',count(m.id))) as message_type1_in_group
from user_group ug
join user u on ug.id=u.group_id
join message m on m.user_id = u.user_id
group by ug.id,ug.name ug.id,ug.name;
Вы можете сделать это быстро и грязно, используя count(distinct):
SELECT ug.id, ug.name,
count(distinct u.id) As "Users in group",
count(distinct m.id) AS "Messages in groups",
count(distinct case when m.type = 1 then m.id end) AS "Message type1 in groups",
count(distinct case when m.type = 2 then m.id end) AS "Message type2 in groups"
FROM user_group ug LEFT JOIN
user u
ON u.group_id = ug.id LEFT JOIN
message m
ON m.user_id = u.id
WHERE ug.id = m.user_id
GROUP BY ug.id;
Вы также можете получить точные подсчеты, агрегируя до, выполняя соединения. Также обратите внимание, что я добавил псевдонимы таблиц, чтобы запрос было легче писать и читать.
Немного отредактируйте ответ Гордона Линоффа.
SELECT a.id, a.name,
COUNT(DISTINCT b.id) AS "Users in group" ,
COUNT(c.id) AS "Messages in groups",
COUNT(DISTINCT CASE WHEN c.type = 1 THEN c.id END) AS "Message type 1 in groups",
COUNT(DISTINCT CASE WHEN c.type = 2 THEN c.id END) AS "Message type 2 in groups"
FROM user_group a LEFT JOIN
USER b
ON b.group_id = a.id LEFT JOIN
message c
ON c.user_id = b.id GROUP BY a.id;
Здесь совокупные результаты извлекаются из сгруппированной таблицы.
Спасибо за отличное дополнение. информация о запросе!
Этот пункт
WHEREвыглядит очень странно. У вас уже есть такое же условие в предложении ON, но WHERE заставит LEFT JOIN возвращать обычный результат INNER JOIN.