如何使用基于多列的CASE进行SUM

时间:2012-06-11 14:14:15

标签: mysql sum case

我现在花了很多年时间试图为我得到的这个SUM查询找到解决方案:

SELECT o.id, o.ordernr, o.datetime, o.status, CONVERT(ROUND(o.shipping,2), CHAR(8)) AS shippingcosts, 
u.id AS uid, u.name, u.surname, u.address, u.number, u.zipcode, u.country, u.email, 
GROUP_CONCAT(CONVERT(op.amount, CHAR(8))) AS amount,         
GROUP_CONCAT(CONVERT(ROUND(op.pprice,2), CHAR(8))) AS pprice, 

IF(     
        u.country!= 'NL', 
        ROUND(SUM(
            CASE
                WHEN op.discount > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discount/100)))
                WHEN op.discountf > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discountf/100)))
                WHEN op.discountf = 0 && op.discount = 0 THEN (op.amount * op.pprice)
            END
        ) + o.shipping,2),
        ROUND((SUM(
            CASE
                WHEN op.discount > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discount/100)))
                WHEN op.discountf > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discountf/100)))
                WHEN op.discountf = 0 && op.discount = 0 THEN ((op.amount * op.pprice)*1.19)
            END
        )*1.19) + o.shipping,2)
) AS total, 

GROUP_CONCAT(CONVERT(p.id, CHAR(8))) AS pid, 
SUM(p.weight) AS weight, 
FROM orders AS o
INNER JOIN users AS u ON o.uid = u.id 
INNER JOIN order_products AS op ON op.oid = o.id
INNER JOIN products AS p ON op.pid = p.id
GROUP BY o.id

我想要实现的是,如果op.discount不为null或op.discountf不为null,并且op.discount和op.discountf都为null的每一行,则获取每一行的总和。

此时似乎mysql正在总结所有总数...... ??

有人可以帮助我吗?

Thnx提前(很多)

2 个答案:

答案 0 :(得分:0)

我在这里注意到的一些事情......

- 您要转换所有整数,还是将点数据类型转换为字符?你想如何让MySQL对字符求和?

SELECT o.id, o.ordernr, o.datetime, o.status, CONVERT(ROUND(o.shipping,2), CHAR(8)) AS shippingcosts, 
u.id AS uid, u.name, u.surname, u.address, u.number, u.zipcode, u.country, u.email, 
GROUP_CONCAT(CONVERT(op.amount, CHAR(8))) AS amount,         
GROUP_CONCAT(CONVERT(ROUND(op.pprice,2), CHAR(8))) AS pprice, 

- 从未见过group_concat中的CONVERT函数,这是参考手册显示的代码GROUP_CONCAT([DISTINCT] expr [,expr ...]              [ORDER BY {unsigned_integer | col_name | EXPR}                  [ASC | DESC] [,col_name ...]]              [SEPARATOR str_val]) - 此外,如果你继续四舍五入,你将不会得到正确的结果,只是把它丢去那里不确定你是否关心。我认为有太多的聚合正在进行,这可能会令人困惑。

IF(     
    u.country!= 'NL', 

- 你没有在选择中围绕这些吗?你需要在这里再绕一圈吗? - 每行还有折扣和折扣吗?如果他们两个都适合你的前两个CASE结构,两次...... - 看起来您还需要基于重量的运费

    ROUND(SUM(
        CASE
            WHEN op.discount > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discount/100)))
            WHEN op.discountf > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discountf/100)))
            WHEN op.discountf = 0 && op.discount = 0 THEN (op.amount * op.pprice)
        END) + o.shipping,2),

- 为什么两次运行相同的CASE结构?一个要加* 1.19?

    ROUND((SUM(
        CASE
            WHEN op.discount > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discount/100)))
            WHEN op.discountf > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discountf/100)))
            WHEN op.discountf = 0 && op.discount = 0 THEN ((op.amount * op.pprice)*1.19)
        END)*1.19) + o.shipping,2)
) AS total, 

GROUP_CONCAT(CONVERT(p.id, CHAR(8))) AS pid, 
SUM(p.weight) AS weight, 
FROM orders AS o
INNER JOIN users AS u ON o.uid = u.id 
INNER JOIN order_products AS op ON op.oid = o.id
INNER JOIN products AS p ON op.pid = p.id
GROUP BY o.id

我个人会尝试做这样的事情(可能不会只调整内连接):

SELECT * FROM products as p
(SELECT o.id, o.ordernr, o.datetime, o.status, CONVERT(ROUND(o.shipping, 2), CHAR(8)) AS     ShippingCosts,
u.id AS U_ID, u.name, u.surname, u.address, u.number, u.zipcode, u.coutnry, u.email, 
op.amount as Amount, op.pprice as Price, 
SUM((op.amount * op.pprice)-(op.discount/100)) as SubTotal, 
SUM((op.amount * op.pprice)-(op.discountf/100)) as SubTotal2,
SUM(p.weight * o.shipping) as Shipping_Charges,
SUM(SubTotal + SubTotal2 + Shipping_Charges)) as o
inner join users AS u ON o.U_ID = u.id
WHERE u.country != 'NL';

- 抱歉,我发现现在有3个内连接。我会将所有这些总结汇总到另一个表

的表中

SELECT订单编号订单ID订单日期从订单为O. 内部连接订购产品为OP ON订单ID =订购产品ID或订单ID,以SUM(小计), 按订单ID分组;

创建一个表来保存这些字段然后只需对应于订单号或订单ID的user_ID进行内部联接,应该有一个外键可以使联接更容易

SELECT订单ID,订单号,订单日期,订单发货,订单产品,订单金额,SUM(订单子总计)FROM Orders_Total 内联接用户为U.U_ID = u.id

上的U.

我没有考虑到舍入或组转换,这听起来像客户端可以做的一些前端工作,但计算很简单,但我真的喜欢你的查询,我只是想把它分解对你而言,抱歉这里有很多。

答案 1 :(得分:0)

你说,“我想要实现的是,如果op.discount不为null或op.discountf不为null,并且op.discount和op.discountf的每一行都得到每行的总和是空的......“如果是这种情况,我建议在case语句的WHEN条件中添加条件,专门针对NULL值进行测试,而不是将op.discount和op.discountf视为保存值,这些值将相应地进行评估当与0比较时,“NULL< 0”评估为NULL,而不是零......我不确定这将如何影响你的case语句?可以在here找到有关在控制语句中使用NULL值的详细信息。

当我第一次看到这个问题时,我认为我可能会反对它的存在......但是在我仔细观察之后,我实际上并没有被冒犯。这并没有多说,因为我喜欢写这样的查询。可能有一种更清洁的方式来做你正在做的事情,但我不明白为什么你的方式不应该工作。我确实在这一行的末尾看到了一个逗号:

SUM(p.weight) AS weight,

......我认为你不想要那里?我重新格式化了查询...不是更好,只是有点不同。帮助我更清楚地看到你在做什么。可以帮助别人,所以我将它包含在下面。其他人可能不喜欢这种格式,所以我没有把它作为对问题的编辑。现在发布这个答案是因为我到目前为止所做的/注意到的事情可能会帮助其他人。如果/正如我所看到的那样,我会编辑以改善我的“答案”。

SELECT
    o.id,
    o.ordernr,
    o.datetime,
    o.status,
    CONVERT(ROUND(o.shipping,2), CHAR(8)) AS shippingcosts, 
    u.id AS uid,
    u.name,
    u.surname,
    u.address,
    u.number,
    u.zipcode,
    u.country,
    u.email, 
    GROUP_CONCAT(CONVERT(op.amount, CHAR(8))) AS amount,         
    GROUP_CONCAT(CONVERT(ROUND(op.pprice, 2), CHAR(8))) AS pprice, 
    IF(     
        u.country != 'NL', 
        ROUND(SUM(
            CASE
                WHEN op.discount > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discount / 100)))
                WHEN op.discountf > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discountf / 100)))
                WHEN op.discountf = 0 && op.discount = 0 THEN (op.amount * op.pprice)
            END
        ) + o.shipping, 2),
        ROUND((SUM(
            CASE
                WHEN op.discount > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discount / 100)))
                WHEN op.discountf > 0 THEN ((op.amount * op.pprice) - ((op.amount * op.pprice) * (op.discountf / 100)))
                WHEN op.discountf = 0 && op.discount = 0 THEN ((op.amount * op.pprice) * 1.19)
            END
        ) * 1.19) + o.shipping, 2)
    ) AS total, 
    GROUP_CONCAT(CONVERT(p.id, CHAR(8))) AS pid, 
    SUM(p.weight) AS weight,
FROM
    orders o INNER JOIN users u
        ON o.uid = u.id 
    INNER JOIN order_products op
        ON o.id = op.oid
    INNER JOIN products p
        ON op.pid = p.id
GROUP BY o.id