Понимание использования нескольких сумм с левыми соединениями в mysql - PullRequest
0 голосов
/ 05 апреля 2020

Используя команду GROUP BY, можно СЛЕДУТЬ СОЕДИНЯТЬ несколько таблиц и при этом получить желаемое количество строк из первой таблицы.

Например,

SELECT b.title 
FROM books `b`
LEFT JOIN orders `o` 
ON o.bookid = b.id 
LEFT JOIN authors `a` 
ON b.authorid = a.id 
GROUP BY b.id

Однако, поскольку за сценой MYSQL выполняет декартово произведение для таблиц, если вы включите более одной команды SUM, вы получите неправильные значения на основе всех скрытых строк. (Проблема здесь объяснена довольно хорошо.)

SELECT b.title,SUM(o.id) as sales,SUM(a.id) as authors    
FROM books `b`
LEFT JOIN orders `o` 
ON o.bookid = b.id 
LEFT JOIN authors `a` 
ON b.authorid = a.id 
GROUP BY b.id

На SO есть несколько ответов , большинство из которых используют подзапросы в JOINS но у меня возникают проблемы с применением их в этом довольно простом случае.

Как настроить вышеуказанное так, чтобы получить правильные суммы?

Редактировать

Пример

books
id|title|authorid
1|Huck Finn|1
2|Tom Sawyer|1
3|Python Cookbook|2

orders
id|bookid
1|1
2|1
3|2
4|2
5|3
6|3

authors
id|author
1|Twain
2|Beazley
2|Jones

The «правильный ответ» для общего числа авторов Python Кулинарной книги равен 2. Однако, поскольку существует два объединения, а общий набор данных расширяется путем объединения по числу заказов, SUM (a.id) будет равно 4.

Ответы [ 3 ]

2 голосов
/ 05 апреля 2020

Вы правы, что, объединив несколько таблиц, вы не получите ожидаемых результатов. Но в этом случае вы должны использовать COUNT() вместо SUM() и рассчитывать отдельные заказы или авторов. Также по вашему замыслу вы должны считать имена авторов, а не id s таблицы authors:

SELECT b.title, 
  COUNT(DISTINCT o.id) as sales,
  COUNT(DISTINCT a.author) as authors    
FROM books `b`
LEFT JOIN orders `o` ON o.bookid = b.id 
LEFT JOIN authors `a` ON b.authorid = a.id 
GROUP BY b.id, b.title

См. demo . Результаты:

| title           | sales | authors |
| --------------- | ----- | ------- |
| Huck Finn       | 2     | 1       |
| Tom Sawyer      | 2     | 1       |
| Python Cookbook | 2     | 2       |
1 голос
/ 05 апреля 2020

При работе с отдельными агрегатами рекомендуется объединять их перед объединением.

Ваша модель данных вводит в заблуждение, из-за чего создается впечатление, что книга написана только одним автором (на что ссылается books.authorid) в то время как этот «идентификатор» вообще не является идентификатором автора.

Ваша главная проблема: Вы не считаете! Мы считаем COUNT. Но вы по ошибке добавляете значения идентификаторов с помощью SUM.

Вот правильный запрос, в котором я собираюсь перед объединением и использованием псевдонимов, чтобы бороться с путаницей и, таким образом, повысить удобочитаемость и удобство сопровождения запроса.

SELECT
  b.title,
  COALESCE(o.order_count, 0) AS sales,
  COALESCE(a.author_count, 0) AS authors
FROM (SELECT title, id AS book_id, authorid AS author_group_id FROM books) b
LEFT JOIN
(
  SELECT id as author_group_id, COUNT(*) as author_count
  FROM authors
  GROUP BY id
) a ON a.author_group_id = b.author_group_id
LEFT JOIN
(
  SELECT bookid AS book_id, COUNT(*) as order_count
  FROM orders
  GROUP BY bookid
) o ON o.book_id = b.book_id
ORDER BY b.title;
0 голосов
/ 05 апреля 2020

Я не думаю, что ваш запрос будет работать так, как вы ожидали.

Предположим, у одной книги может быть 3 авторов.

Для авторов :

Таким образом, у вас будет три строки для этой книги в таблице книг, каждая для каждого автора.

Таким образом,

SUM(b.authorid) 

дает вам правильный ответ в вашем случае.

Для Приказов :

, которые вы должны использовать подобъект, подобный

LEFT JOIN (SELECT SUM(id) o_sum,bookid  FROM orders GROUP BY bookid) `o` 
ON o.bookid = b.id 

Вы должны действительно пересмотреть свой подход с книгами и авторами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...