是否可以通过 SQL(oracle)中的截断时间戳进行排序?
Posted
技术标签:
【中文标题】是否可以通过 SQL(oracle)中的截断时间戳进行排序?【英文标题】:Is it possible to order by truncated timestamp in SQL (oracle)? 【发布时间】:2021-12-29 19:29:09 【问题描述】:我有一个用例,我想按时间订购,但要按一定的分辨率。例如,我的模式将时间戳保存到小数点后 9 位(纳秒精度),但我只想按分钟排序并使用不同的字段在该分钟内排序。我试过这个
select * from myTable order by (cast(myTimeStamp at time zone 'UTC' as timestamp) - to_timestamp('01-JAN-01'))/1000000000*60 desc, id desc;
将时间戳转换为纪元,然后除以得到分钟精度。但这给出了错误的顺序。此外,当我对上述命令进行转储以了解返回的数据类型时,我看到数据类型:typ=190,但我找不到 in the oracle docs 类型,这让我更加困惑。
所以我想知道我错过了什么?应该可以通过截断(到分钟)的时间戳进行排序,不胜感激。
【问题讨论】:
【参考方案1】:将TIMESTAMP WITH TIME ZONE
转换为UTC
时区,以便您可以比较相同的时间,然后TRUNC
将其返回到分钟的开头:
SELECT *
FROM myTable
ORDER BY
TRUNC(myTimeStamp at time zone 'UTC', 'MI') DESC,
id DESC;
其中,对于样本数据:
CREATE TABLE myTable(
id NUMBER,
myTimestamp TIMESTAMP WITH TIME ZONE
);
INSERT INTO myTable(id, myTimestamp)
SELECT 1, TIMESTAMP '1970-01-01 00:00:00 UTC' FROM DUAL UNION ALL
SELECT 2, TIMESTAMP '1970-01-01 00:00:00 America/New_York' FROM DUAL UNION ALL
SELECT 3, TIMESTAMP '1970-01-01 00:00:00 Asia/Hong_Kong' FROM DUAL UNION ALL
SELECT 4, TIMESTAMP '1970-01-01 00:00:00 Europe/Paris' FROM DUAL UNION ALL
SELECT 5, TIMESTAMP '1970-01-01 01:00:00 UTC' FROM DUAL UNION ALL
SELECT 6, TIMESTAMP '1970-01-01 01:00:00 America/New_York' FROM DUAL UNION ALL
SELECT 7, TIMESTAMP '1970-01-01 01:00:00 Europe/Berlin' FROM DUAL;
输出:
ID MYTIMESTAMP 6 01-JAN-70 01.00.00.000000 AMERICA/NEW_YORK 2 01-JAN-70 00.00.00.000000 AMERICA/NEW_YORK 5 01-JAN-70 01.00.00.000000 UTC 7 01-JAN-70 01.00.00.000000 EUROPE/BERLIN 1 01-JAN-70 00.00.00.000000 UTC 4 01-JAN-70 00.00.00.000000 EUROPE/PARIS 3 01-JAN-70 00.00.00.000000 ASIA/HONG_KONG
如果您想查看在排序过程中使用的转换为 UTC 的值,只需将其添加到输出中:
SELECT t.*,
TO_CHAR(TRUNC(myTimeStamp at time zone 'UTC', 'MI'), 'YYYY-MM-DD HH24:MI:SS')
AS converted_ts
FROM myTable t
ORDER BY
TRUNC(myTimeStamp at time zone 'UTC', 'MI') DESC,
id DESC;
哪些输出:
ID MYTIMESTAMP CONVERTED_TS 6 01-JAN-70 01.00.00.000000 AMERICA/NEW_YORK 1970-01-01 06:00:00 2 01-JAN-70 00.00.00.000000 AMERICA/NEW_YORK 1970-01-01 05:00:00 5 01-JAN-70 01.00.00.000000 UTC 1970-01-01 01:00:00 7 01-JAN-70 01.00.00.000000 EUROPE/BERLIN 1970-01-01 00:00:00 1 01-JAN-70 00.00.00.000000 UTC 1970-01-01 00:00:00 4 01-JAN-70 00.00.00.000000 EUROPE/PARIS 1969-12-31 23:00:00 3 01-JAN-70 00.00.00.000000 ASIA/HONG_KONG 1969-12-31 16:00:00
如果您只使用TRUNC
而不转换为公共时区,那么它将根据日期和时间组件进行排序,而不考虑时区的相对差异。
db小提琴here
【讨论】:
【参考方案2】:你为什么不把时间戳截断为分钟?
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:Mi:ss';
Session altered.
SQL> select systimestamp col_1,
2 trunc(systimestamp, 'mi') col_2
3 from dual;
COL_1 COL_2
---------------------------------------- -------------------
29.12.21 20:32:50,178000 +01:00 29.12.2021 20:32:00
SQL>
那么你会
order by trunc(timestamp_column, 'mi'),
yet_another_column
【讨论】:
这似乎有效,但我的查询作为应用程序的一部分运行。因此,使用这种方法,我需要为每个数据库连接正确更改会话? 否;我更改它只是为了设置格式(因为默认情况下,它设置为 DD.MM.YY,所以你不会看到任何区别)。您只需要 ORDER BY 子句。以上是关于是否可以通过 SQL(oracle)中的截断时间戳进行排序?的主要内容,如果未能解决你的问题,请参考以下文章