MariaDB/MySQL TO_SECONDS 和聚合函数
MariaDB/MySQL TO_SECONDS and AGGREGATE functions
我想使用 TO_SECONDS 和聚合函数 (AVG, COUNT) 来总结我的 table。然而,结果并不是我所期望的。这是一个例子 table:
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 Fiddle: 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 的用法?
这是一个奇怪的数据类型问题。以下确实有效:
select cast(to_seconds(ts) as decimal(20, 0)) as tsec, avg(val)
from mytable
group by tsec;
我不知道为什么 to_seconds()
的 return 值足够大,可以在您 select 时存储该值,但在您 select 时却被转换为整数使用 group by
.
我无法回答为什么会发生这种情况,但确认这在 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 ),但自那以后,除了确认之外,没有 activity 添加到该错误报告中。
有趣的是,如果我们使用 to_seconds(max(t))
或 max(to_seconds(t))
[= 而不是 to_seconds(t)
,则可以避免该问题34=](从理论上讲,这应该产生相同的结果,因为无论如何我们都在 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 |
+---------------------+---------------+---------------------+--------------------+--------------------+
我想使用 TO_SECONDS 和聚合函数 (AVG, COUNT) 来总结我的 table。然而,结果并不是我所期望的。这是一个例子 table:
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 Fiddle: 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 的用法?
这是一个奇怪的数据类型问题。以下确实有效:
select cast(to_seconds(ts) as decimal(20, 0)) as tsec, avg(val)
from mytable
group by tsec;
我不知道为什么 to_seconds()
的 return 值足够大,可以在您 select 时存储该值,但在您 select 时却被转换为整数使用 group by
.
我无法回答为什么会发生这种情况,但确认这在 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 ),但自那以后,除了确认之外,没有 activity 添加到该错误报告中。
有趣的是,如果我们使用 to_seconds(max(t))
或 max(to_seconds(t))
[= 而不是 to_seconds(t)
,则可以避免该问题34=](从理论上讲,这应该产生相同的结果,因为无论如何我们都在 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 |
+---------------------+---------------+---------------------+--------------------+--------------------+