简体   繁体   English

MySQL中SUM的多行总和

[英]SUM of multiple rows of SUMs in MySQL

I have a query that returns a total column for every order : 我有一个查询,返回每个ordertotal列:

SELECT o.id, o.created, o.status, o.shipping,
SUM(op.price*op.amount*(1+op.tax/100.0))+COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)+COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0) AS total

FROM orders AS o
LEFT OUTER JOIN order_products as op ON o.id=op.order_id
GROUP BY o.id;

第一个查询的输出

Output of the query 查询的输出

Now I want to calculate the total revenue, so that would be the SUM of these total columns. 现在,我要计算总收入,因此将是这些total列的total

I tried using a subquery like this: 我尝试使用像这样的子查询:

SELECT 
SUM(total) FROM (
    SELECT
    SUM(op.price*op.amount*(1+op.tax/100.0))+COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)+COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0) AS total
    FROM orders AS o
    LEFT OUTER JOIN order_products as op ON o.id=op.order_id
    GROUP BY o.id
) AS foo
;

第二个查询的输出

Output of the query 查询的输出

However: 然而:

  • The result column was named SUM(total) , not foo 结果列名为SUM(total) ,而不是foo
    • Seems like the AS foo is used for the subquery, not for the top-level SUM() 似乎AS foo用于子查询,而不是顶级SUM()
  • Without the AS foo , it doesn't work 没有AS foo ,它将无法正常工作
  • The result that this query returned might have been incorrect, but that could have been due to rounding . 该查询返回的结果可能不正确, 但这可能是由于rounding引起的

How should the query, to SUM multiple rows of SUMs, look? 查询以求和SUM的多行,应该如何看待?

Note: Those NULL totals almost certainly won't exist in production, but it'd still be better to use COALESCE(x, 0) just to make sure the query executes correctly. 注意: 这些NULL总数 几乎肯定不会在生产中存在,但是最好使用 COALESCE(x, 0)来确保查询正确执行。 Seems like this SUM() is fine with NULL values? 似乎这样的SUM()可以使用NULL值吗?

when you want to alias name to total you have o set it before from not after your select and for checking null you have to set a value for that: 如果您想为名称加上别名,则必须在选择之前而不是之后进行设置,并且要检查是否为null,必须为此设置一个值:

  SELECT 
    SUM(COALESCE(a.total,0)) as foo FROM (
        SELECT
        SUM(op.price*op.amount*(1+op.tax/100.0))+COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)+COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0) AS total
        FROM orders AS o
        LEFT OUTER JOIN order_products as op ON o.id=op.order_id
        GROUP BY o.id
    ) AS a
SELECT
  SUM(
     COALESCE(op.order_total, 0)
    +COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)
    +COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0)
  )
    AS grand_total
FROM
  orders   AS o
LEFT OUTER JOIN
(
  SELECT
    order_id,
    SUM(price*amount*(1+tax/100.0))  AS order_total
  FROM
    order_products
  GROUP BY
    order_id
)
  AS op
    ON o.id=op.order_id

EDIT: 编辑:

You've said that : 你说过:
- SUM(x+y+z) / COUNT(op.order_total) gives 506 SUM(x+y+z) / COUNT(op.order_total)506
- AVG(x+y+z) gives 532 AVG(x+y+z)得到532

This implies to me that some of the x+y+z rows are NULL when x is NOT NULL , therefore it appears that y or z are NULL . 在我看来,这意味着当x NOT NULLNULL时,某些x+y+z NOT NULL ,因此看来yzNULL

As y and z are COALESCE(?, 0) * (1+o.shipping_tax/100.0) , it feels like shipping_tax is sometimes NULL . 由于yzCOALESCE(?, 0) * (1+o.shipping_tax/100.0) ,因此感觉 shipping_tax有时为NULL

Try this query... 试试这个查询...

SELECT
  SUM(
     COALESCE(op.order_total, 0)
    +COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)
    +COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0)
  )
    AS grand_total,
  AVG(
     COALESCE(op.order_total, 0)
    +COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)
    +COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0)
  )
    AS grand_average,
  COUNT(
     COALESCE(op.order_total, 0)
    +COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)
    +COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0)
  )
    AS grand_row_count,
  COUNT(
    *
  )
    AS set_row_count,
  COUNT(
    o.shipping_tax
  )
    AS shipping_tax_row_count,
  AVG(
     COALESCE(op.order_total, 0)
    +(COALESCE(o.shipping, 0)+COALESCE(o.payment_fee, 0))
     *COALESCE(1+o.shipping_tax/100.0, 1)
  )
    AS revised_grand_average
FROM
  orders   AS o
LEFT OUTER JOIN
(
  SELECT
    order_id,
    SUM(price*amount*(1+tax/100.0))  AS order_total
  FROM
    order_products
  GROUP BY
    order_id
)
  AS op
    ON o.id=op.order_id

I expect that... 希望 ...
- grand_average == grand_total / grand_row_count grand_average == grand_total / grand_row_count
- set_row_count > grand_row_count set_row_count > grand_row_count
- grand_row_count == shipping_tax_row_count grand_row_count == shipping_tax_row_count

If so, then the revised_grand_average should be useful to you. 如果是这样,那么revised_grand_average应该对您有用。

If not, then hopefully this gives you a place to start investigating. 如果不是,那么希望这给您一个开始调查的地方。

You don't need a subquery. 您不需要子查询。 Just remove the GROUP BY from the original query: 只需从原始查询中删除GROUP BY

SELECT SUM(op.price*op.amount*(1+op.tax/100.0))+COALESCE(o.shipping, 0)*(1+o.shipping_tax/100.0)+COALESCE(o.payment_fee, 0)*(1+o.shipping_tax/100.0) AS total
FROM orders o LEFT OUTER JOIN
     order_products op
     ON o.id = op.order_id;

This will do the calculation over all the rows. 这将对所有行进行计算。 It should be faster than two levels of aggregation. 它应该快于两个级别的聚合。

The result will be in a column called total . 结果将在称为total的列中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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