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 ...

一种方法:计数子选择中的network_users(SELECT子句中的子查询)

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             |

View on DB Fiddle

另一种方法:在派生表中执行“预聚合”(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           |

View on DB Fiddle

一些注意事项:

  • 确保userid表中的users是UNIQUE或PRIMARY KEY。否则,从mysql 5.7开始会出现错误。
  • 我用users amusers 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:在没有别名的联接查询中获取多个同名列? [复制]

MySQL 一个查询中的多个联接?

3.09 聚集和联接

“where”条件在 JPA 中的联接查询中无法正常工作(本机查询)

具有内部联接、多个分组依据和最小最大值的 Linq 查询

在内部联接中重用 mysql 子查询