在 Informix 中将时间戳舍入到整整一个小时 SQL

Round timestamps up to a whole hour in Informix SQL

我有一个数据库 table,它有一个名为 dlv_tm 的列,其中包含格式为 hh:mm:ss

的时间戳

大多数时间戳都是整小时,例如09:00:00、11:00:00 等,但有些是故意偏移一分钟,例如08:59:00, 10:59:00, 等等,以区分它们。

然而,这意味着从这个 table 中提取数据会得到非常分散的结果,我想汇总忽略这些偏移量的数据,即处理具有该一分钟偏移量的记录,就好像偏移量是在那里。

换句话说,当遇到时间戳为08:59:00的记录时,我想拉取时间戳为09:00:00的记录。

我尝试了不同的方法,使用 CASE/WHEN 语句和 datediff 来确定我是否应该在时间戳中添加一分钟,我没有开始工作,或者 ROUND,这没有产生预期的结果,我认为这与 hh:mm:ss 格式是非标准 date/time 格式有关。

任何tips/suggestions?

使用 Informix 12.10FC8DE 我可以使用以下内容:

CREATE TABLE my_dlv_tm
(
    id INTEGER
    , tmstmp DATETIME HOUR TO SECOND
);

INSERT INTO my_dlv_tm VALUES (1, '09:00:00');
INSERT INTO my_dlv_tm VALUES (2, '08:59:00');
INSERT INTO my_dlv_tm VALUES (3, '09:01:00');
INSERT INTO my_dlv_tm VALUES (4, '00:00:00');
INSERT INTO my_dlv_tm VALUES (5, '23:59:00');
INSERT INTO my_dlv_tm VALUES (6, '00:01:00');

在示例table中我使用了以下语句:

SELECT
    id
    , tmstmp
    , ROUND(tmstmp::DATETIME YEAR TO SECOND, 'HH')::DATETIME HOUR TO SECOND AS rounded_tmstmp
FROM
    my_dlv_tm;


 id tmstmp   rounded_tmstmp

  1 09:00:00 09:00:00
  2 08:59:00 09:00:00
  3 09:01:00 09:00:00
  4 00:00:00 00:00:00
  5 23:59:00 00:00:00
  6 00:01:00 00:00:00

6 row(s) retrieved.

直接使用 DATETIME HOUR TO SECOND 会产生以下错误:

1263: A field in a datetime or interval value is incorrect or an illegal operation

所以我将DATETIME HOUR TO SECOND转换为DATETIME YEAR TO SECOND,使用ROUND函数,最后将结果转换回DATETIME HOUR TO SECOND

我不确定为什么它需要强制转换,根据我在 IBM® Informix® 12.10 ROUND Function 阅读的内容,我不明白 ROUNDDATETIME 参数需要一个日期组件。

这是处理它的另一种方法。我分两步工作(TDQD 的一种形式——测试驱动的查询设计)。一个主要问题是,将 30 分钟添加到 DATETIME HOUR TO SECOND 值(例如 23:59:00)会溢出 DATETIME HOUR TO SECOND 的 acceptable 值的范围。

第 1 步:使用 DATETIME YEAR TO SECOND

+ CREATE TABLE round_datetime
(
    id SERIAL NOT NULL PRIMARY KEY,
    dt DATETIME YEAR TO SECOND NOT NULL
);
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 09:00:00');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 08:59:00');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 09:01:00');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 00:00:00');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 23:29:59');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 23:30:00');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 23:59:00');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 00:01:00');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 00:29:59');
+ INSERT INTO round_datetime VALUES (0, '2017-12-18 00:30:00');
+ SELECT id,
       dt,
       EXTEND(EXTEND(dt + 30 UNITS MINUTE, YEAR TO HOUR), YEAR TO SECOND)
  FROM round_datetime
 ORDER BY dt;

SERIAL  DATETIME YEAR TO SECOND DATETIME YEAR TO SECOND
4       2017-12-18 00:00:00     2017-12-18 00:00:00
8       2017-12-18 00:01:00     2017-12-18 00:00:00
9       2017-12-18 00:29:59     2017-12-18 00:00:00
10      2017-12-18 00:30:00     2017-12-18 01:00:00
2       2017-12-18 08:59:00     2017-12-18 09:00:00
1       2017-12-18 09:00:00     2017-12-18 09:00:00
3       2017-12-18 09:01:00     2017-12-18 09:00:00
5       2017-12-18 23:29:59     2017-12-18 23:00:00
6       2017-12-18 23:30:00     2017-12-19 00:00:00
7       2017-12-18 23:59:00     2017-12-19 00:00:00

表达式EXTEND(EXTEND(dt + 30 UNITS MINUTE, YEAR TO HOUR), YEAR TO SECOND)如果分阶段分解可能会更简单,这就是它的发展方式:

dt + 30 UNITS MINUTE

每次增加 30 分钟,愉快地结束到第二天的早些时候。

EXTEND(dt + 30 UNITS MINUTE, YEAR TO  HOUR

这将删除 MINUTES 和 SECONDS,截断值(这就是添加 30 分钟的原因)。

EXTEND(EXTEND(dt + 30 UNITS MINUTE, YEAR TO  HOUR), YEAR TO SECOND)

这将恢复 MINUTES 和 SECONDS,但将它们设置为零。双重 EXTEND 操作至关重要。例如,尝试仅使用 EXTEND(dt + 30 UNITS MINUTE, HOUR TO SECOND) 不会将答案的分钟和秒部分归零。

第 2 步:使用 DATETIME HOUR TO SECOND

这与上一步非常相似,但利用了以下事实:当您将带有 YEAR 的 DATETIME HOUR TO SECOND 值扩展到 DAY 组件时,它们会采用与当前日期对应的值。因此:

+ CREATE TABLE round_time
(
    id SERIAL NOT NULL PRIMARY KEY,
    dt DATETIME HOUR TO SECOND NOT NULL
);
+ INSERT INTO round_time VALUES (0, '09:00:00');
+ INSERT INTO round_time VALUES (0, '08:59:00');
+ INSERT INTO round_time VALUES (0, '09:01:00');
+ INSERT INTO round_time VALUES (0, '00:00:00');
+ INSERT INTO round_time VALUES (0, '23:29:59');
+ INSERT INTO round_time VALUES (0, '23:30:00');
+ INSERT INTO round_time VALUES (0, '23:59:00');
+ INSERT INTO round_time VALUES (0, '00:01:00');
+ INSERT INTO round_time VALUES (0, '00:29:59');
+ INSERT INTO round_time VALUES (0, '00:30:00');
+ SELECT id,
       dt,
       EXTEND(dt, YEAR TO SECOND),
       EXTEND(EXTEND(EXTEND(dt, YEAR TO SECOND) + 30 UNITS MINUTE, YEAR TO HOUR), YEAR TO SECOND),
       EXTEND(EXTEND(EXTEND(dt, YEAR TO SECOND) + 30 UNITS MINUTE, YEAR TO HOUR), HOUR TO SECOND)
  FROM round_time
 ORDER BY dt;
SERIAL  DATETIME HOUR TO SECOND DATETIME YEAR TO SECOND DATETIME YEAR TO SECOND DATETIME HOUR TO SECOND
4       00:00:00        2017-12-16 00:00:00     2017-12-16 00:00:00     00:00:00
8       00:01:00        2017-12-16 00:01:00     2017-12-16 00:00:00     00:00:00
9       00:29:59        2017-12-16 00:29:59     2017-12-16 00:00:00     00:00:00
10      00:30:00        2017-12-16 00:30:00     2017-12-16 01:00:00     01:00:00
2       08:59:00        2017-12-16 08:59:00     2017-12-16 09:00:00     09:00:00
1       09:00:00        2017-12-16 09:00:00     2017-12-16 09:00:00     09:00:00
3       09:01:00        2017-12-16 09:01:00     2017-12-16 09:00:00     09:00:00
5       23:29:59        2017-12-16 23:29:59     2017-12-16 23:00:00     23:00:00
6       23:30:00        2017-12-16 23:30:00     2017-12-17 00:00:00     00:00:00
7       23:59:00        2017-12-16 23:59:00     2017-12-17 00:00:00     00:00:00

最后一栏似乎是您想要的答案。显然,如果 table 中已经有一个 suitable DATE 列,则可以改用它,特别是如果您希望日期成为分析的一部分。然后,您将在步骤 1 SQL 上使用一些变体来产生适当的结果。

与所有 date/time 计算一样(至少在 Informix 中),表达式很冗长。