[英]Understanding use of multiple SUMs with LEFT JOINS in mysql
使用 GROUP BY 命令,可以 LEFT JOIN 多个表,并且仍然从第一个表中获取所需的行数。
例如,
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
关于这个有很多答案,大多数在 JOINS 中使用子查询,但我无法将它们应用于这个相当简单的案例。
您如何调整上述内容以获得正确的 SUM?
编辑
例子
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
Python Cookbook 的作者总数的“正确答案”为 2。但是,由于有两个连接,并且整个数据集按订单数的连接扩展,因此 SUM(a.id) 将为 4。
你是正确的,通过加入多个表你不会得到预期的结果。
但在这种情况下,您应该使用COUNT()
而不是SUM()
并计算不同的订单或作者。
同样根据您的设计,您应该计算作者的姓名,而不是表authors
的id
:
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
见演示。
结果:
| title | sales | authors |
| --------------- | ----- | ------- |
| Huck Finn | 2 | 1 |
| Tom Sawyer | 2 | 1 |
| Python Cookbook | 2 | 2 |
在处理单独的聚合时,在加入之前聚合是一种很好的方式。
您的数据 model 非常令人困惑,使它看起来像一本书仅由一位作者撰写(由books.authorid
引用),而这个“ID”根本不是作者的 ID。
你的主要问题是:你不算数! 我们用COUNT
。 但是您错误地将 ID 值与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;
我认为您的查询不会像您预期的那样工作。
假设一本书可能有3 个作者。
对于作者:
因此,您的 books 表中将为该书提供三行,每一行代表每个作者。
所以一个
SUM(b.authorid)
在你的情况下给你正确的答案。
对于订单:
您必须使用子选择,例如
LEFT JOIN (SELECT SUM(id) o_sum,bookid FROM orders GROUP BY bookid) `o`
ON o.bookid = b.id
你真的应该重新考虑你对书籍和作者的态度。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.