MySQL 一列的 SUM,ID 列的 DISTINCT

问题描述 投票:0回答:5

我正在尝试创建订单摘要报告,但无法在单个查询中提取所有所需数据。

我要提取的数据:

  • 小计 - 所有销售价格的总和
  • 交付总计 - 所有订单的总交付交付总计
  • 订单 - 不同订单 ID 的计数
  • 数量 - 所有订购数量的总和

订单表(本例已简化)

| orderId | deliveryTotal | total |
|---------|---------------|-------|
| 1       | 5             | 15    |
| 2       | 5             | 15    |
| 3       | 7.50          | 27.50 |

订购商品表

| orderItemId | orderId | productId | salePrice | quantity |
|-------------|---------|-----------|-----------|----------|
| 1           | 1       | 1         | 10        | 1        |
| 2           | 2       | 1         | 10        | 1        |
| 3           | 3       | 1         | 10        | 1        |
| 4           | 3       | 2         | 10        | 1        |

我当前提取此数据的查询是

SELECT
    SUM(i.salePrice * i.quantity) as subtotal,
    SUM(DISTINCT o.deliveryTotal) as deliveryTotal,
    COUNT(DISTINCT o.orderId) as orders,
    SUM(i.quantity) as quantity
FROM orderItems i
INNER JOIN orders o ON o.orderId = i.orderId

这会产生正确的小计、订单计数和数量总和。但是当我在 17.50 之后,交货总额返回为 12.50。如果我这样做

SUM(o.deliveryTotal)
它将返回 25.

编辑:期望的结果

| subtotal | deliveryTotal | orders | quantity |
|----------|---------------|--------|----------|
| 40.00    | 17.50         | 3      | 4        |
mysql
5个回答
19
投票

https://tiaashish.wordpress.com/2014/01/31/mysql-sum-for-distinct-rows-with-left-join/

这是一篇博客文章,准确地展示了我正在寻找的内容。也许这也可以帮助其他人。

公式是这样的:

SUM(o.deliveryTotal) * COUNT(DISTINCT o.orderId) / COUNT(*)


4
投票

由于连接,

SUM(DISTINCT deliveryTotal)
聚合被应用到包含值
5, 5, 7.5, 7.5
(不同的
5 + 7.5 = 12.5
)的行集。

如果您简单地这样做,

SUM()
所作用的行会变得更加明显

SELECT o.*
FROM orderItems i
INNER JOIN orders o ON o.orderId = i.orderId

相反,您要求的是

SUM()
中所有值的
deliveryTotal
,无论它们在与
orderItems
的连接中的位置如何。这意味着您需要在不同的级别应用聚合。

由于您不打算稍后添加

GROUP BY
,因此最简单的方法是使用子选择,其目的只是在整个表中获取
SUM()

SELECT
    SUM(i.salePrice * i.quantity) as subtotal,
    -- deliveryTotal sum as a subselect
    (SELECT SUM(deliveryTotal) FROM orders) as deliveryTotal,
    COUNT(DISTINCT o.orderId) as orders,
    SUM(i.quantity) as quantity
FROM orderItems i
INNER JOIN orders o ON o.orderId = i.orderId

通常不鼓励使用子选择,但子选择不会造成显着的性能损失,与使用连接的替代方法没有什么不同。无论如何,计算都必须在与现有连接不同的单独聚合上完成。 其他方法会在

CROSS JOIN
子句中放置一个子查询
FROM
,它执行的操作与我们在子查询中放置的操作相同。性能是一样的。


1
投票

在内部选择中选择每个订单,然后将其汇总

Select 
SUM(subtotal) as subtotal,
sum(deliveryTotal) as deliveryTotal,
count(1) as orders,
sum(quantity) as quantity
from (
SELECT 
    SUM(i.salePrice * i.quantity) as subtotal,
    o.deliveryTotal as deliveryTotal,
    SUM(i.quantity) as quantity
FROM orders o
INNER JOIN orderItems i ON o.orderId = i.orderId
group by o.orderId) as sub

0
投票

以下查询结果正是您所需要的

SELECT SUM(conctable.subtotal),
SUM(conctable.deliveryTotal),
SUM(conctable.orders),
SUM(conctable.quantity) from  
(SELECT SUM(i.salePrice * i.quantity) as subtotal,
    o.deliveryTotal as deliveryTotal,
    COUNT(DISTINCT o.orderId) as orders,
    SUM(i.quantity) as quantity
FROM orderItems i
JOIN orders o ON o.orderId = i.orderId group by i.orderid) as conctable;

0
投票

有一种方法可以通过替换来做到这一点:

SUM(columnToAdd)

ROUND(SUM(DISTINCT columnToAdd + distinctId/10000), 2)

所以在这种情况下,它将是:

ROUND(SUM(DISTINCT deliveryTotal + orderId/10000), 2)

这会将 DISTINCT(5.0001, 5.0002, 7.5003, 7.5003) = 5.0001 + 5.0002 + 7.5003 = 17.5006 加起来,然后将其舍入为 17.50。由于两个 7.5 来自 id 为 3 的同一订单,因此它们将作为重复项被删除。但这两个 5 来自不同的顺序,因此不是重复的。

这只适用于 ID 号较小的情况(除以 10000 不会干扰 SUM)。如果你有更大的 id 数字,你必须除以一个更大的数字并输入 FORMAT 来强制 MySQL 使用超过 4 位小数:

ROUND(SUM(DISTINCT FORMAT(columnToAdd + distinctId/10000000000, 12)), 2)

我承认这是对旧帖子的一个相当丑陋的答案,但我今天正在寻找解决方案并记得过去做过类似的事情。

© www.soinside.com 2019 - 2024. All rights reserved.