繁体   English   中英

了解在 mysql 中通过 LEFT JOINS 使用多个 SUM

[英]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()并计算不同的订单或作者。
同样根据您的设计,您应该计算作者的姓名,而不是表authorsid

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM