【问题标题】:Mysql - Sum is not returning results when making a pivotMysql - 在进行数据透视时,Sum 不返回结果
【发布时间】:2016-01-10 02:51:57
【问题描述】:

我在 MySQL 中有以下查询:

SELECT
    r.id_account AS 'account_id',
    a.name AS 'account_name',
    r.id_status_g 'status_id',
    sg.name AS 'status_name',
    r.transaction_type AS 'transtype_id',
    tt.name AS 'transtype_name',
    COUNT(r.id) AS 'count',
    r.currency_code,
    SUM(r.amount/100) AS 'amount'
FROM transaction_r r, account a, transaction_type tt, status_g sg
WHERE
    r.id_account = a.id AND
    r.transaction_type = tt.id AND
    r.id_status_g = sg.id AND
    r.c_date >= '2015-10-01 00:00:00' AND
    r.c_date <= '2015-10-09 23:59:59'
GROUP BY
    r.id_status_g, r.currency_code
ORDER BY
    r.id_account, r.id_status_g;

输出如下结果:

+------------+--------------+-----------+-------------+--------------+----------------+-------+---------------+--------+
| account_id | account_name | status_id | status_name | transtype_id | transtype_name | count | currency_code | amount |
+------------+--------------+-----------+-------------+--------------+----------------+-------+---------------+--------+
|          8 | testing      |         1 | Approved    |            1 | Sale           |     1 | USD           |     20 |
|          8 | testing      |         3 | Declined    |            1 | Sale           |     1 | USD           |     20 |
|          8 | testing      |         4 | Error       |            1 | Sale           |    10 | USD           |    200 |
|          8 | testing      |         5 | Refunded    |            1 | Sale           |     1 | USD           |     20 |
|          8 | testing      |         6 | Chargeback  |            1 | Sale           |     1 | USD           |     20 |
+------------+--------------+-----------+-------------+--------------+----------------+-------+---------------+--------+------+-------+---------------+--------+

上面的信息是正确的,但我想每个货币代码和账户 ID 只返回一行,所以我使用以下查询进行了透视:

SELECT
    a.name AS 'account_name',
    r.transaction_type AS 'transtype_id',
    tt.name AS 'transtype_name',
    r.currency_code,
    CASE WHEN r.id_account = 8 AND r.id_status_g = 4 THEN SUM(IF (r.id_status_g = 4, 1,0)) END AS 'error',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 3 THEN SUM(IF (r.id_status_g = 3, 1, 0)) END AS 'declined',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 6 THEN SUM(IF (r.id_status_g = 6, 1, 0)) END AS 'chargeback',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 5 THEN SUM(IF (r.id_status_g = 5, 1, 0)) END AS 'refunded',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 1 THEN SUM(IF (r.id_status_g = 1, 1, 0)) END AS 'approved',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 4 THEN SUM(IF (r.id_status_g = 4, ROUND(r.amount/100, 2), 0)) END AS 'amount_error',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 3 THEN SUM(IF (r.id_status_g = 3, ROUND(r.amount/100, 2), 0)) END AS 'amount_declined',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 6 THEN SUM(IF (r.id_status_g = 6, ROUND(r.amount/100, 2), 0)) END AS 'amount_chargeback',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 5 THEN SUM(IF (r.id_status_g = 5, ROUND(r.amount/100, 2), 0)) END AS 'amount_refunded',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 1 THEN SUM(IF (r.id_status_g = 1, ROUND(r.amount/100, 2), 0)) END AS 'amount_approved'
FROM transaction_r r, account a, transaction_type tt, status_g sg
WHERE
    r.id_account = a.id AND
    r.transaction_type = tt.id AND
    r.id_status_g = sg.id AND
    r.c_date >= '2015-10-01 00:00:00' AND
    r.c_date <= '2015-10-09 23:59:59'
GROUP BY
    r.id_account, r.currency_code

它返回的正是我想要的方式,但是只有每组案例的第一个总和有效,其余的返回空值。

+--------------+--------------+----------------+---------------+-------+----------+------------+----------+----------+--------------+-----------------+-------------------+-----------------+-----------------+
| account_name | transtype_id | transtype_name | currency_code | error | declined | chargeback | refunded | approved | amount_error | amount_declined | amount_chargeback | amount_refunded | amount_approved |
+--------------+--------------+----------------+---------------+-------+----------+------------+----------+----------+--------------+-----------------+-------------------+-----------------+-----------------+
| testing      |            1 | Sale           | USD           |    10 | NULL     | NULL       | NULL     | NULL     |          200 | NULL            | NULL              | NULL            | NULL            |
+--------------+--------------+----------------+---------------+-------+----------+------------+----------+----------+--------------+-----------------+-------------------+-----------------+-----------------+

如果我进行不同的分组,我可以看到每个金额总和有一行,并且每个总和都有一个正确的总和值,其余为 null(一行具有正确的批准金额总和,其余返回 null,以下是拒绝金额等)

如果总和有误,我希望它们都不起作用,表连接也是如此,但每组案例中的第一个都起作用,这让我感到困惑。我执行查询的方式有问题吗?这是我在 MySQL 中进行的第一次支点尝试,任何反馈都将不胜感激

谢谢

【问题讨论】:

  • 你很接近 - 我已经尝试解释以下问题。我还没有测试过 - 如果您发布带有示例架构等的 SQLfiddle.com,我很高兴 :)

标签: mysql select sum pivot


【解决方案1】:

未经测试 - 但我相信这就是你想要的......

记住SELECTGROUP BY 的结果相反...所以r.id_* 有点毫无意义(在非/后聚合上下文中)...

然而SUM() 正在聚合 - 它的内容应用于每条记录(不仅仅是GROUP BY 的输出。

因此,您将IF(...) 放入其中是正确的(我的意思是每个SUM())。松开外部的条件(您制作的CASE)并将r.id_account 移动到现有的IF(...) 中,您应该是金色的。

你很亲密:)

SELECT
    a.name AS 'account_name',
    r.transaction_type AS 'transtype_id',
    tt.name AS 'transtype_name',
    r.currency_code,
    SUM(IF(r.id_account = 8 AND r.id_status_g = 4, 1,0)) AS 'error',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 3, 1, 0)) AS 'declined',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 6, 1, 0)) AS 'chargeback',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 5, 1, 0)) AS 'refunded',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 1, 1, 0)) AS 'approved',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 4, ROUND(r.amount/100, 2), 0)) AS 'amount_error',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 3, ROUND(r.amount/100, 2), 0)) AS 'amount_declined',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 6, ROUND(r.amount/100, 2), 0)) AS 'amount_chargeback',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 5, ROUND(r.amount/100, 2), 0)) AS 'amount_refunded',
    SUM(IF(r.id_account = 8 AND r.id_status_g = 1, ROUND(r.amount/100, 2), 0)) AS 'amount_approved'
FROM transaction_r r, account a, transaction_type tt, status_g sg
WHERE
    r.id_account = a.id AND
    r.transaction_type = tt.id AND
    r.id_status_g = sg.id AND
    r.c_date >= '2015-10-01 00:00:00' AND
    r.c_date <= '2015-10-09 23:59:59'
GROUP BY
    r.id_account, r.currency_code

【讨论】:

  • 你和 OP 在选择列表中的字段比分组列表中的字段多。
  • @Shadow MySQL 允许这样做,除非您打开 ONLY_FULL_GROUP_BY 选项。
  • 是的 - MySQL 允许做一些其他引擎无法做的事情。
  • @Shadow 尽管 Barmar 是正确的,但您正确地使查询“符合”标准,这是一种很好的做法,我会考虑到这一点,感谢您的通知 :)
  • @Juan 关于 NULL - 是的,因为该案例从未评估过(您没有“默认”/“其他”部分),它实际上“没有返回值”。因此为空。 // 关于格式:我缩进了 4 个字符(或者,您也可以在 textarea [在您的浏览器中] 选择它,然后单击工具栏上的“{}”按钮)。希望有帮助!
【解决方案2】:

我相信问题是您在选择列表中添加了一些不属于任何分组函数的字段,例如 sum() 并且也不在 group by 列表中:

SELECT
    a.name AS 'account_name',
    r.transaction_type AS 'transtype_id',
    tt.name AS 'transtype_name',
    r.currency_code,
    CASE WHEN r.id_account = 8 AND r.id_status_g = 4 THEN SUM(IF (r.id_status_g = 4, 1,0)) END AS 'error',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 3 THEN SUM(IF (r.id_status_g = 3, 1, 0)) END AS 'declined',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 6 THEN SUM(IF (r.id_status_g = 6, 1, 0)) END AS 'chargeback',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 5 THEN SUM(IF (r.id_status_g = 5, 1, 0)) END AS 'refunded',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 1 THEN SUM(IF (r.id_status_g = 1, 1, 0)) END AS 'approved',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 4 THEN SUM(IF (r.id_status_g = 4, ROUND(r.amount/100, 2), 0)) END AS 'amount_error',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 3 THEN SUM(IF (r.id_status_g = 3, ROUND(r.amount/100, 2), 0)) END AS 'amount_declined',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 6 THEN SUM(IF (r.id_status_g = 6, ROUND(r.amount/100, 2), 0)) END AS 'amount_chargeback',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 5 THEN SUM(IF (r.id_status_g = 5, ROUND(r.amount/100, 2), 0)) END AS 'amount_refunded',
    CASE WHEN r.id_account = 8 AND r.id_status_g = 1 THEN SUM(IF (r.id_status_g = 1, ROUND(r.amount/100, 2), 0)) END AS 'amount_approved'
FROM transaction_r r, account a, transaction_type tt, status_g sg
WHERE
    r.id_account = a.id AND
    r.transaction_type = tt.id AND
    r.id_status_g = sg.id AND
    r.c_date >= '2015-10-01 00:00:00' AND
    r.c_date <= '2015-10-09 23:59:59'
GROUP BY
    a.name, r.transaction_type, tt.name, r.currency_code

我知道 mysql 允许这种语法,但是,如果您省略这些字段,那么 mysql 将从满足条件的“物理”记录顺序中的第一条记录中获取这些字段的值。

【讨论】:

  • 我实际上在发布之前尝试将分组字段添加到group by,但正如@barmar 在下面的 cmets 上所建议的那样,MySQL 实际上默认允许这样做并且它没有对结果进行任何更改
猜你喜欢
  • 2015-01-09
  • 2018-11-15
  • 1970-01-01
  • 2013-04-10
  • 1970-01-01
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 2016-09-03
相关资源
最近更新 更多