MySQL查询:SUM计算重复行

时间:2017-05-24 20:52:36

标签: mysql count sum left-join

我有一个查询为我们的客户生成损益表,但我在加入订单表时遇到问题,导致SUM乘以费用条目数。

我有以下表格:

  • user_report_categories,“urc”,这是报告用户的类别标题
  • user_report_expenses,“ure”,这是个人费用,带有“adjusted_cost”和“expense_date”。这些可能会或可能没有与之相关的订单,但在这种情况下,我们只关注与订单相关的费用。每个订单可能有多个费用,但每个费用/订单总是在不同的类别中。
  • 订单,“o”,其中包含“agree_fee”,“balance”,当然还有“id”

报告需要在用户选择的日期范围内每月包含一列,并在单元格中显示计算值。

查询如下:

SELECT
SUBSTRING(MONTHNAME(STR_TO_DATE(m, '%m')), 1, 3) AS month,
COUNT(o.id) AS "# of Orders",
ROUND(SUM(o.agreed_fee) - SUM(o.balance), 2) AS "Total Income",
ROUND(SUM(ure.adjusted_cost), 2) AS "Total Expenses",
ROUND(SUM(o.agreed_fee) - SUM(o.balance) - SUM(ure.adjusted_cost), 2) AS "Profit & Loss",
"" AS "",
ROUND(SUM(ure.adjusted_cost) / COUNT(ure.id), 2) AS "% of Expenses per Order",
ROUND((SUM(o.agreed_fee) - SUM(o.balance)) / COUNT(ure.id), 2) AS "Average Fee per Order",
ROUND(((SUM(o.agreed_fee) - SUM(o.balance)) / COUNT(ure.id)) - (SUM(ure.adjusted_cost) / COUNT(ure.id)), 2) AS "Average P/L per Order"

FROM ( 
    SELECT y, m FROM 
    (SELECT YEAR('2016-01-01') y) years, 
    (SELECT 1 m UNION ALL SELECT 2 UNION ALL SELECT 3) months
) ym 

LEFT JOIN user_report_categories AS urc ON urc.user_id = 48 
LEFT JOIN user_report_entries AS ure ON ure.user_category_id = urc.id AND YEAR(ure.expense_date) = y AND MONTH(ure.expense_date) = m 
LEFT JOIN orders AS o ON o.id = ure.order_id 
WHERE urc.report_type = 'expense' AND urc.user_id = 48  AND ure.order_id IS NOT NULL
GROUP BY y, m

结果:

month,# of Orders,Total Income,Total Expenses,Profit & Loss,,% of Expenses per Order,Average Fee per Order,Average P/L per Order
Jan,387,36400.00,5921.17,30478.83,,15.30,94.06,78.76
Feb,559,55327.50,8165.12,47162.38,,14.61,98.98,84.37
Mar,736,74785.00,10261.07,64523.93,,13.94,101.61,87.67

我确定通过将订单ID添加到组中来将订单乘以费用数量

GROUP BY y, m, o.id

并查看每行有多个订单的新结果:

month,# of Orders,Total Income,Total Expenses,Profit & Loss,,% of Expenses per Order,Average Fee per Order,Average P/L per Order
Jan,6,360.00,31.95,328.05,,5.33,60.00,54.68
Jan,1,0.00,30.24,-30.24,,30.24,0.00,-30.24
Jan,6,1200.00,141.74,1058.26,,23.62,200.00,176.38
Jan,6,540.00,160.97,379.03,,26.83,90.00,63.17
Jan,6,540.00,98.77,441.23,,16.46,90.00,73.54
Jan,8,720.00,167.44,552.56,,20.93,90.00,69.07
... etc ...

或者,当我从group-by中删除o.id时,改为将order of lines更改为count distinct:

COUNT(DISTINCT o.id) AS "# of Orders",

我得到了#个订单的正确值,但当然由于重复,SUM订单表值仍然不正确的其他值。

month,# of Orders,Total Income,Total Expenses,Profit & Loss,,% of Expenses per Order,Average Fee per Order,Average P/L per Order
Jan,71,36400.00,5921.17,30478.83,,15.30,94.06,78.76
Feb,105,55327.50,8165.12,47162.38,,14.61,98.98,84.37
Mar,146,74785.00,10261.07,64523.93,,13.94,101.61,87.67

我不确定我是否对此采取了良好的方法,但在一次查询中执行这一代对我来说是一个巨大的优势,所以我试图将它拼凑在一起。如何在不同的订单ID上获取SUM订单表值,或以其他方式更正查询以正确计算?谢谢!

答案

@Sal踢了我一脚,最后的查询结束了。我认为它也涵盖了评论中提出的所有问题。

SELECT 
SUBSTRING(MONTHNAME(STR_TO_DATE(m, '%m')), 1, 3) AS month,
orders AS "# of Orders",
round(total_income,2) AS "Total Income",
round(total_expenses,2) AS "Total Expenses",
round(total_income-total_expenses,2) AS "Profit & Loss",
"" AS "",
round(total_expenses/orders,2) AS "% of Expenses per Order",
round(total_income/orders,2) AS "Average Fee per Order",
round( (total_income/orders)-(total_expenses/orders), 2) AS "Average P/L per Order"

        FROM ( 
            SELECT m, 
            (SELECT count(o.id)
                FROM orders o
                WHERE year(o.datetime) = ym.y
                AND month(o.datetime) = ym.m AND o.user_id = 48
                AND o.cancelled = 0
            ) AS orders,
            (SELECT IFNULL(sum(o.agreed_fee - o.balance), 0)
                FROM orders AS o
                WHERE year(o.datetime) = ym.y
                AND month(o.datetime) = ym.m 
                AND o.user_id = 48
                AND o.cancelled = 0
            ) AS total_income,
            (SELECT IFNULL(sum(ure.adjusted_cost),0)
                FROM user_report_entries AS ure
                INNER JOIN user_report_categories AS urc ON urc.id = ure.user_category_id
                  WHERE year(ure.expense_date) = ym.y
                AND month(ure.expense_date) = ym.m 
                AND urc.user_id = 48  AND urc.id NOT IN (6287) ) AS total_expenses
            FROM ( SELECT 2017 y, 1 m  UNION SELECT 2017, 2 UNION SELECT 2017, 3
            ) ym

            GROUP BY y, m
        ) t

1 个答案:

答案 0 :(得分:1)

我希望你觉得这很有用:

SELECT substring( monthname( str_to_date(m,'%m'), 1, 3) month
     , orders "# of Orders"
     , round(total_income,2) "Total Income"
     , round(total_expenses,2) "Total Expenses"
     , round(total_income-total_expenses,2) "Profit & Loss"
     , round(total_expenses/orders,2) "% of Expenses per Order"
     , round(total_income/orders,2) "Average Fee per Order"
     , round( (total_income/orders)-(total_expenses/orders), 2) "Average P/L per Order"
  FROM ( SELECT m
              , ( SELECT count(distinct ure.order_id)
                    FROM user_report_entries ure
                    WHERE year(ure.expense_date) = ym.y
                      AND month(ure.expense_date) = ym.m
                ) orders
              , ( SELECT sum(o.agreed_fee - o.balance)
                    FROM user_report_entries ure
                      INNER JOIN orders o
                        ON o.id = ure.order_id             
                    WHERE year(ure.expense_date) = ym.y
                      AND month(ure.expense_date) = ym.m 
                ) total_income
              , sum(ure.adjusted_cost) total_expenses
           FROM ( SELECT 2016 y, 1 m
                  UNION
                  SELECT 2016, 2
                  UNION
                  SELECT 2016, 3
                ) ym
             LEFT JOIN user_report_entries ure
               ON    year(ure.expense_date) = ym.y
                 AND month(ure.expense_date) = ym.m
             LEFT JOIN user_report_categories urc
               ON    urc.id = ure.user_category_id
           WHERE urc.user_id = 48
             AND urc.report_type = 'expense'
           GROUP BY y, m
       ) t