#mysql #left-join #multiple-tables
#mysql #левое соединение #несколько таблиц
Вопрос:
Это должно быть довольно просто, но я не могу придумать никакого решения и не могу найти ответ где-нибудь…
Я получил таблицу «пользователи»
и одну таблицу «блоги» (user_id, blogpost)
и одну таблицу «сообщения» (user_id, message)
Я хотел бы получить следующий результат:
User | count(blogs) | count(messages)
Jim | 0 | 3
Tom | 2 | 3
Tim | 0 | 1
Foo | 2 | 0
Итак, что я сделал:
SELECT u.id, count(b.id), count(m.id) FROM `users` u
LEFT JOIN blogs b ON b.user_id = u.id
LEFT JOIN messages m ON m.user_id = u.id
GROUP BY u.id
Очевидно, что это не работает, потому что второе левое соединение относится к блогам, а не к пользователям. Есть предложения?
Ответ №1:
Во-первых, если вам нужно только значение count, вы можете выполнить подвыборки:
select u.id, u.name,
(select count(b.id) from blogs where userid = u.id) as 'blogs',
(select count(m.id) from messages where userid = u.id) as 'messages'
from 'users'
Обратите внимание, что это всего лишь простой пример sql, у меня здесь нет базы данных mysql, чтобы протестировать ее прямо сейчас.
С другой стороны, вы могли бы выполнить объединение, но вы должны использовать an outer join
для включения пользователей без блогов, но с сообщениями. Это означало бы, что вы получаете несколько пользователей несколько раз, поэтому группа by была бы полезна.
Комментарии:
1. @user993692 — Это зависит от подзапроса. Современные базы данных достаточно умны, чтобы оптимизировать подвыборку, и в этом случае вам нужен только поиск по ключу, который довольно легкий (предполагается, что у вас нет квадриллиона пользователей).
Ответ №2:
Если вы используете агрегатную функцию в select, SQL свернет все ваши строки в одну строку.
Чтобы получить более 1 строки, вы должны использовать group by
предложение.
Затем SQL будет генерировать итоговые данные для каждого пользователя.
Самый быстрый вариант
SELECT
u.id
, (SELECT(COUNT(*) FROM blogs b WHERE b.user_id = u.id) as blogcount
, (SELECT(COUNT(*) FROM messages m WHERE m.user_id = u.id) as messagecount
FROM users u
Почему ваш код не работает
SELECT u.id, count(b.id), count(m.id)
FROM users u
LEFT JOIN blogs b ON b.user_id = u.id <<-- 3 matches multiplies # of rows *3
LEFT JOIN messages m ON m.user_id = u.id <<-- 5 matches multiplies # of rows *5
GROUP BY u.id
Счетчик будет отключен, потому что вы считаете повторяющиеся элементы.
Простое исправление, но будет медленнее, чем вариант 1
Если вы считаете только отдельные идентификаторы, вы получите правильные подсчеты:
SELECT u.id, count(DISTNICT b.id), count(DISTINCT m.id)
FROM users u
LEFT JOIN blogs b ON b.user_id = u.id
LEFT JOIN messages m ON m.user_id = u.id
GROUP BY u.id
Комментарии:
1. Я
group by
уже получил, просто забыл записать это. Но результат по-прежнему неверный, будет выглядеть так:User | count(blogs) | count(messages) Jim | 0 | 0 Tom | 2 | 2 Tim | 0 | 0 Foo | 2 | 2