一种方法:计数子选择中的network_users
(SELECT子句中的子查询)
sum()在具有多个联接的MySQL查询中不能正常工作(group by不能按预期工作)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sum()在具有多个联接的MySQL查询中不能正常工作(group by不能按预期工作)相关的知识,希望对你有一定的参考价值。
我有订单,网络和用户表,我需要为每个用户获取订单总数]和订单总数],并且用户在每个用户拥有的同一个网络中进行计数。 带有示例数据的SQLFiddle: http://sqlfiddle.com/#!9/dcbeea/1 users.userid,orders.id-唯一主键。
在此示例中,检查用户#24行:total_orders
,total_revenue,network_users的值不正确。用户#24的当前结果:总订单数:6,总收入:350,网络用户数:6。
用户#24的预期结果:总订单数:3,总收入:175,网络用户数:2。
这是SQL请求:
在这里返回不正确的值(超出了应有的值,由于网络表连接的缘故,它求和了几次)。SELECT u.*, count(o.id) AS total_orders, sum(o.total) AS total_revenue, count(un.userid) as network_users /* Users count in same network */ FROM users u LEFT JOIN orders o ON o.userid=u.userid LEFT JOIN users am ON u.ownerid = am.userid LEFT JOIN users bdr ON u.bdrid = bdr.userid LEFT JOIN networks n ON u.networkid = n.networkid LEFT JOIN users un ON n.networkid=un.networkid GROUP BY u.userid ORDER BY u.userid DESC;
问题1:total_orders
和total_revenue
我可以通过添加不同的-count(distinct(o.id))AS total_orders来修复total_orders,但是这对求和无效,因为我无法设置仅对不同ID求和无法在SQL中进行设置。
[您可以在SQLFiddle示例中看到问题-用户#24应该具有total_revenue = 175,但是您看到它的计算结果为350。正如我看到的那样,这是因为两个不同的用户与用户#24关联到同一个网络(网络#1)有。
问题2:count(un.userid)as network_users-如果我不将count(disctinct(un.userid))添加为network_users,这将无法正常工作。如果没有'distinct',这将显示我所看到的整个网络(而不是总用户数与当前用户具有相同networkid的网络)。在SQL示例中,用户ID#24的“ network_users”应该为2(因为该网络中只有2个用户),但是结果中我看到6。
问题:
如何更改SQL请求以获得正确的数学预期结果?我有表格Orders,Networks和Users,我需要获取每个用户的总订单数和订单总数,并且用户数与每个用户都在同一网络中。带示例的SQLFiddle ...
SELECT u.userid, count(o.id) AS total_orders, coalesce(sum(o.total), 0) AS total_revenue, ( SELECT count(*) FROM users un WHERE un.networkid = u.networkid ) as network_users FROM users u LEFT JOIN orders o ON o.userid=u.userid GROUP BY u.userid, u.networkid ORDER BY u.userid DESC;
结果:
| userid | total_orders | total_revenue | network_users |
| ------ | ------------ | ------------- | ------------- |
| 40 | 1 | 75 | 1 |
| 37 | 0 | 0 | 2 |
| 33 | 0 | 0 | 1 |
| 24 | 3 | 175 | 2 |
另一种方法:在派生表中执行“预聚合”(FROM子句中的子查询)
SELECT u.userid,
count(o.id) AS total_orders,
coalesce(sum(o.total), 0) AS total_revenue,
u.network_users
FROM (
SELECT u.userid, count(un.userid) as network_users
FROM users u
LEFT JOIN users un ON un.networkid = u.networkid
GROUP BY u.userid
) u
LEFT JOIN orders o ON o.userid=u.userid
GROUP BY u.userid
ORDER BY u.userid DESC;
结果:
| userid | network_users | total_orders | total_revenue |
| ------ | ------------- | ------------ | ------------- |
| 40 | 1 | 1 | 75 |
| 37 | 2 | 0 | 0 |
| 33 | 1 | 0 | 0 |
| 24 | 2 | 3 | 175 |
一些注意事项:
- 确保
userid
表中的users
是UNIQUE或PRIMARY KEY。否则,从mysql 5.7开始会出现错误。 - 我用
users am
和users bdr
删除了JOIN。您没有在查询中使用它们。如果您想从中选择任何内容,则可以放回它们。 - 我还通过
networks
表删除了JOIN。您可以只使用users
列将networkid
表与其自身连接。 - 使用
COALESCE()
作为SUM()
将NULL
转换为0
。
为什么您的查询未能返回预期结果?因为您正在将一个用户与来自同一网络的所有其他用户加入订单。因此,订单数和总金额乘以同一网络中的用户数量。
以这种方式看。当执行JOIN
时,首先将表中所有行的组合放到一个大的临时表中(在过滤掉所有不适用的表之后)。
Then
COUNT()
和SUM()
是针对此大表计算的。通常这是不正确的。通常,解决方法是first
设计一个查询,该查询使用从中间表中获取正确总和所需的最小表数。 然后再执行您可能需要的JOINs
。(一种替代方法(有时)是采用子查询进行聚合或提供JOINs
的等效项。
一种方法:计数子选择中的network_users
(SELECT子句中的子查询)
以这种方式看。当执行JOIN
时,首先将表中所有行的组合放到一个大的临时表中(在过滤掉所有不适用的表之后)。
Then
以上是关于sum()在具有多个联接的MySQL查询中不能正常工作(group by不能按预期工作)的主要内容,如果未能解决你的问题,请参考以下文章
PHP/MySQL:在没有别名的联接查询中获取多个同名列? [复制]