#mysql #sum #aggregate
#mysql #сумма #агрегировать
Вопрос:
Я хотел бы получить еще один столбец с процентами символов, используемых любым пользователем.
Для этого мне нужно взять общее количество символов, полученных для всех сообщений пользователя в его / ее posts.title и posts.тело суммирует их, а после суммирует все символы всех пользователей.
Я получаю эту таблицу:
'name', 'chars_title', 'chars_body', 'chars_total'
'user1', '7', '6', '13'
'user2', '27', '23', '50'
'user3', '6', '5', '11'
С помощью этого запроса:
SELECT users.name,
sum(length(posts.title)) as chars_title,
sum(length(posts.body)) chars_body,
sum(length(posts.title) length(posts.body)) chars_total
FROM test.posts posts
JOIN test.users users
ON posts.user_id=users.id
GROUP BY users.name
ORDER BY chars_total DESC;
Могу ли я получить процентное соотношение символов, используемых пользователем, с помощью chars_total и функции, которая дает мне общее значение char_total?
Например, функция, которая суммирует 13 50 11 по уже агрегированным столбцам?
Комментарии:
1. Размышление о том, может быть, решение — это всего лишь подзапрос.
Ответ №1:
Вы можете CROSS JOIN
этот запрос:
SELECT SUM(LENGTH(title) LENGTH(body)) total FROM posts
который возвращает общее количество символов всех пользователей в таблице:
SELECT u.name,
p.chars_title,
p.chars_body,
p.chars_title p.chars_body chars_total,
100.0 * (p.chars_title p.chars_body) / c.total percentage
FROM users u
INNER JOIN (
SELECT user_id,
SUM(LENGTH(title)) chars_title,
SUM(LENGTH(body)) chars_body
FROM posts
GROUP BY user_id
) p ON p.user_id = u.id
CROSS JOIN (SELECT SUM(LENGTH(title) LENGTH(body)) total FROM posts) c
Обратите внимание, что, возможно, вам следует использовать CHAR_LENGTH()
вместо LENGTH()
.
Комментарии:
1. У меня ошибка таким образом, мне нужно проверить это лучше.
2. @Salvio Я уже исправил опечатки. запрос синтаксически корректен: db-fiddle.com/f/tBHJs6dhp6YFCH4R9FNgov/0
3. Я нашел другое решение, которое я опубликовал: создаю временную таблицу и помещаю сумму в переменную, чтобы использовать ее в конечном запросе. Как вы думаете, что это дешевле? @forpas?
4. Этот комментарий является ответом на (теперь удаленный) комментарий другого пользователя, поэтому я должен удалить его тоже.
5. Вам нужно будет протестировать производительность. MySQL разрешает ВНУТРЕННЕЕ соединение без предложения ON (которое на самом деле является ПЕРЕКРЕСТНЫМ СОЕДИНЕНИЕМ).
Ответ №2:
Если вы используете MySQL 8 , то вы можете использовать SUM()
в качестве аналитической функции здесь:
SELECT
u.name,
SUM(LENGTH(p.title)) chars_title,
SUM(LENGTH(p.body)) chars_body,
SUM(LENGTH(p.title) LENGTH(p.body)) chars_total,
100.0 * SUM(LENGTH(p.title) LENGTH(p.body)) /
SUM(SUM(LENGTH(p.title) LENGTH(p.body))) OVER ()
AS chars_total_pct
FROM test.posts p
INNER JOIN test.users u
ON p.user_id = u.id
GROUP BY
u.name
ORDER BY
chars_total DESC;
Комментарии:
1. А с MYSQL 5.7 ?
2. …вы можете обновить?
:-)
3. К сожалению, я не могу, это устаревший проект.
Ответ №3:
На данный момент я решил таким образом:
1) Я создал временную таблицу, чтобы поместить первый результат запроса:
CREATE TEMPORARY TABLE IF NOT EXISTS total SELECT users.name,
sum(length(posts.title)) as chars_title,
sum(length(posts.body)) chars_body,
sum(length(posts.title) length(posts.body)) chars_total
FROM test.posts posts
JOIN test.users users
ON posts.user_id=users.id
GROUP BY users.name
ORDER BY chars_total DESC;
2) Вычислил сумму в временной таблице и поместил ее в переменную:
SELECT sum(chars_total) FROM total INTO @total_chars;
3) Сделайте запрос к временной таблице, используя переменную:
SELECT name,
chars_title,
chars_body,
chars_total,
ROUND(chars_total*100/@total_chars, 0) as percentage
FROM total;
Я думаю, что это немного грязное решение, но пока все в порядке.