【问题标题】:MariaDB/MySQL TO_SECONDS and AGGREGATE functionsMariaDB/MySQL TO_SECONDS 和 AGGREGATE 函数
【发布时间】:2017-01-26 05:59:46
【问题描述】:

我想使用 TO_SECONDS 和聚合函数 (AVG, COUNT) 来汇总我的表。然而,结果并不是我所期望的。这是一个示例表:

MariaDB [test]> select * from mytable;
+----+---------------------+------+
| id | ts                  | val  |
+----+---------------------+------+
|  1 | 2016-01-01 01:02:03 |    1 |
|  2 | 2016-01-01 01:02:04 |    2 |
|  3 | 2016-01-01 01:02:04 |    3 |
|  4 | 2016-01-01 01:02:05 |    4 |
|  5 | 2016-01-01 01:02:05 |    5 |
+----+---------------------+------+

查询 #1(确定):

MariaDB [test]> select to_seconds(ts) as tsec from mytable;
+-------------+
| tsec        |
+-------------+
| 63618829323 |
| 63618829324 |
| 63618829324 |
| 63618829325 |
| 63618829325 |
+-------------+

查询 #2 (?):

MariaDB [test]> select to_seconds(ts) as tsec, avg(val) mval from mytable group by tsec;
+------------+------+
| tsec       | mval |
+------------+------+
| 2147483647 |    3 |
+------------+------+

预期结果:

+-------------+------+
| tsec        | mval |
+-------------+------+
| 63618829323 |    1 |
| 63618829324 |  2.5 |
| 63618829325 |  4.5 |
+-------------+------+

SQL 小提琴:http://sqlfiddle.com/#!9/17616a/6
MariaDB 版本> mysql Ver 15.1 Distrib 10.1.17-MariaDB,适用于 Linux (x86_64),使用 readline 5.1

当然,我可以使用其他 DATE/TIME 函数(UNIX_TIMESTAMP 等)来执行任务。但是,我想知道为什么结果不同。
我错过了什么?我是否误解了 TO_SECONDS 的用法?

【问题讨论】:

  • 这似乎是一个数据类型问题。返回值被视为整数而不是大整数。

标签: mysql aggregate mariadb


【解决方案1】:

这是一个奇怪的数据类型问题。以下确实有效:

select cast(to_seconds(ts) as decimal(20, 0)) as tsec, avg(val)
from mytable
group by tsec;

我不知道为什么to_seconds() 的返回值在您选择它时会大到足以存储该值,但在您使用group by 时会转换为整数。

【讨论】:

  • 感谢您的快速回答。
【解决方案2】:

我无法回答为什么会发生这种情况,但请确认在 MySQL 版本中仍然会发生这种情况。 5.7.32,并提出一个(笨拙的)解决方法。

例子:

create table Foo (t datetime);
insert into Foo values('2020-01-01 00:00:01');
insert into Foo values('2020-01-02 00:00:01');
insert into Foo values('2020-01-03 00:00:01');
select t, to_seconds(t) from Foo;
+---------------------+---------------+
| t                   | to_seconds(t) |
+---------------------+---------------+
| 2020-01-01 00:00:01 |   63745056001 |
| 2020-01-02 00:00:01 |   63745142401 |
| 2020-01-03 00:00:01 |   63745228801 |
+---------------------+---------------+

到目前为止一切顺利。现在,使用group by

select t, to_seconds(t) from Foo group by t;
+---------------------+---------------+
| t                   | to_seconds(t) |
+---------------------+---------------+
| 2020-01-01 00:00:01 |    2147483647 |
| 2020-01-02 00:00:01 |    2147483647 |
| 2020-01-03 00:00:01 |    2147483647 |
+---------------------+---------------+

每行的to_seconds(t) 值变为 2147483647,等于 2^31-1,即有符号 4 字节整数可表示的最大正值。这看起来像是 MySQL 服务器内部的某种数据转换问题,在不应该发生的情况下。

基本上相同的问题在 2019 年 3 月被报告为 MySQL 错误( https://bugs.mysql.com/bug.php?id=94612 ),但自那以后,除了确认之外,没有任何活动被添加到该错误报告中。

有趣的是,如果我们使用 to_seconds(max(t))max(to_seconds(t)) 代替 to_seconds(t),则可以避免问题(理论上,应该产生相同的结果,因为我们无论如何都在t上分组):

 select t, to_seconds(t), max(t), to_seconds(max(t)), max(to_seconds(t)) from Foo group by t;
+---------------------+---------------+---------------------+--------------------+--------------------+
| t                   | to_seconds(t) | max(t)              | to_seconds(max(t)) | max(to_seconds(t)) |
+---------------------+---------------+---------------------+--------------------+--------------------+
| 2020-01-01 00:00:01 |    2147483647 | 2020-01-01 00:00:01 |        63745056001 |        63745056001 |
| 2020-01-02 00:00:01 |    2147483647 | 2020-01-02 00:00:01 |        63745142401 |        63745142401 |
| 2020-01-03 00:00:01 |    2147483647 | 2020-01-03 00:00:01 |        63745228801 |        63745228801 |
+---------------------+---------------+---------------------+--------------------+--------------------+

【讨论】:

    猜你喜欢
    • 2021-09-09
    • 2013-04-11
    • 1970-01-01
    • 2019-02-01
    • 2023-03-05
    • 2019-02-04
    • 2016-08-03
    • 2021-04-16
    相关资源
    最近更新 更多