【问题标题】:MySQL sum latest values with multiple group by'sMySQL对多个分组的最新值求和
【发布时间】:2020-03-11 13:15:53
【问题描述】:

我需要一些帮助来生成 MySQL 版本 5.7.29 的 MySQL 查询

我拥有的数据集是这样的(示例数据):

| id | serial_number | reading_value | reading_date        | register_type |
|----|---------------|---------------|---------------------|---------------|
| 1  | 123           | 7492.91       | 2019-11-20 15:37:55 | import        |
| 2  | 123           | 7783.3        | 2019-11-25 11:15:47 | import        |
| 3  | 123           | 0             | 2019-11-26 13:34:01 | export        |
| 4  | 123           | 4.01          | 2019-11-27 13:52:23 | export        |
| 5  | 456           | 7404.93       | 2019-11-24 13:31:06 | import        |
| 6  | 456           | 7758.23       | 2019-11-26 13:35:02 | import        |
| 7  | 456           | 0             | 2019-11-20 15:37:55 | export        |
| 8  | 456           | 0             | 2019-11-26 13:34:01 | export        |

我想获得 latest importlatest 的 reading_valuesum export 为每个 serial_number 生成如下数据集:

| serial_number | total_value | latest_reading_date |
|---------------|-------------|---------------------|
| 123           | 7787.31     | 2019-11-27 13:52:23 | <--- id 2 and 4 from above table
| 456           | 7758.23     | 2019-11-26 13:35:02 | <--- id 6 and 8 from above table
  • 在这个结果数据集中,total_valuelatest importsum每个序列号的最新 导出 reading_value
  • latest_reading_dateserial_number 的最新(最新)导入或导出(以最晚者为准)日期

我尝试了以下查询,但它给了我 all importexportsum每个 serial_number 的值,而不仅仅是 latest importlatestsum每个 serial_number 的 em>export 值。

select serial_number, sum(reading_value) as 'total_value', max(reading_date) as 'latest_reading_date'
from t1
group by serial_number

我们将不胜感激。

【问题讨论】:

    标签: mysql sql


    【解决方案1】:

    使用支持聚合值排序的 GROUP_CONCAT 函数有一个棘手的方法。

    SELECT serial_number, 
        SUBSTRING_INDEX(GROUP_CONCAT(IF(register_type = 'import', total_value, NULL) ORDER BY reading_date DESC, id DESC), ',', 1) `latest_import`,
        SUBSTRING_INDEX(GROUP_CONCAT(IF(register_type = 'export', total_value, NULL) ORDER BY reading_date DESC, id DESC), ',', 1) `latest_export`
    FROM t1
    GROUP BY serial_number
    

    解释:

    • GROUP_CONCAT(IF(register_type = 'import', total_value, NULL) ORDER BY reading_date DESC, id DESC) - 将生成一个以逗号分隔的 total_values 列表,其中 import 类型按日期和 ID 排序
    • SUBSTRING_INDEX() - 将从列表中获取第一个值
    • 您想要的值是 latest_import + latest_export(+如果可能,请检查空值),为简洁起见,我省略了它

    【讨论】:

    • 我将它包装在另一个 select 查询中,该查询将 latest_importlatest_export 值加在一起,这似乎对我有用: )
    • 我的问题的扩展:您如何修改您的解决方案以采用最新的 三个 import三个 最新的export 每个序列号的值并将它们加在一起,而不是最新的 import 和最新的 export?我问是因为我也需要为不同的数据集执行此操作。我想基本上使用SUBSTRING_INDEX() 从列表中获取第一、第二和第三个值。不仅是列表中的第一个值。我希望我的要求是有道理的?
    • @MornéLombard 好吧,它更复杂。使用 vanilla MySQL 没有简单的方法可以做到这一点。选项 1:使用 SUBSTRING_INDEX() 获取 3 个最新值,然后使用 (stackoverflow.com/a/6315125/2244262) 等自定义函数计算逗号分隔列表的总和。选项 2:使用 SUBSTRING_INDEX() 将每个值提取到单独的列中,就像在我的解决方案中一样。所以你会得到6列+serial_number。选项 3:在子查询中为每个 serial_number 计算第三大 ID,然后在外部查询中获取 ID >= 子查询中的 ID 的所有值的总和。
    【解决方案2】:

    您可以使用 correlated 子查询进行聚合:

    select t1_1.serial_number, sum(t1_1.reading_value) as total_value, 
           max(t1_1.reading_date) as latest_reading_date
    from t1_1
    where t1_1.reading_date = (select max(t1_2.reading_date) 
                               from t1 as t1_2
                               where t1_2.serial_number = t1_1.serial_number and 
                                     t1_2.register_type = t1_1.register_type
                              )
    group by t1_1.serial_number;
    

    【讨论】:

      【解决方案3】:

      如果我理解正确,您可以在聚合之前使用窗口函数:

      select serial_number, sum(reading_value) as total_value, 
             max(reading_date) as latest_reading_date
      from (select t1.*,
                   row_number() over (partition by serial_number, register_type order by reading_date) as seqnum
            from t1
           ) t
      group by serial_number;
      

      在 MySQL 8.0 之前的版本中,您可以使用关联子查询:

      select serial_number, sum(reading_value) as total_value, 
             max(reading_date) as latest_reading_date
      from t1
      where t1.reading_date = (select max(tt1.reading_date)
                               from t1 tt1
                               where tt1.serial_number = t1.serial_number and
                                     tt1.register_type = t1.register_type
                              )
      group by serial_number;
      

      【讨论】:

      • @Stalinko。 . .大约两年前(2018 年 4 月)发布。
      • 谢谢你。对不起,我忘了说我的版本是5.7.29
      • @GordonLinoff 但在某些设置中,5.7 仍然是首选版本。我个人一直在使用它,因为当我迁移到 v8 时,我的大型生产数据库开始崩溃。
      猜你喜欢
      • 1970-01-01
      • 2021-11-01
      • 2011-08-08
      • 2021-02-19
      • 1970-01-01
      • 2020-10-02
      • 2023-03-28
      • 1970-01-01
      • 2012-03-29
      相关资源
      最近更新 更多