Oracle 23c ROUND 与 DATE 数据类型

drk*_*drk 2 sql oracle date rounding

我遇到过 Oracle 23c 的奇怪行为。据我了解,ROUND 函数中缺少第二个参数应该与显式放置“DAY”参数完全相同。

  SELECT TO_DATE('2024-06-26 15:02:18','YYYY-MM-DD HH24:MI:SS')               AS result                     
     , ROUND(TO_DATE('2024-06-26 15:02:18','YYYY-MM-DD HH24:MI:SS')     )         AS default_result
     , ROUND(TO_DATE('2024-06-26 15:02:18','YYYY-MM-DD HH24:MI:SS')   , 'DAY')    AS day_explicit
  ;
Run Code Online (Sandbox Code Playgroud)

根据 Oracle文档“如果省略 fmt,则日期将四舍五入到最近的一天”,“DAY”参数仅表示“DAY”。

结果看起来像这样 -> day_explicit 列不应该像2024-06-27吗? 在此输入图像描述

MT0*_*MT0 10

ROUND(date_value, 'DAY')舍入到最近的一周开始时间(由会话/数据库参数定义NLS_TERRITORY)。

ROUND(date_value, 'DD')四舍五入到最近的一天。

这记录在ROUND 和 TRUNC 日期函数文档中:

格式模型 舍入或截断单位
DDDDJ

DAY
DY
D
一周的开始日期

例如:

如果您有样本数据:

CREATE TABLE table_name (dt) AS
SELECT TRUNC(DATE '2024-06-26', 'IW') + LEVEL - 1 + INTERVAL '15:02:18' HOUR TO SECOND
FROM   DUAL
CONNECT BY LEVEL <= 7;
Run Code Online (Sandbox Code Playgroud)

你使用:

ALTER SESSION SET NLS_TERRITORY = 'Germany'
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS (DY)';
SELECT dt,
       ROUND(dt)        AS default_result,
       ROUND(dt, 'DAY') AS day_explicit,
       ROUND(dt, 'DD') AS dd_explicit
FROM   table_name;
Run Code Online (Sandbox Code Playgroud)

那么输出是:

DT 默认结果 DAY_EXPLICIT DD_EXPLICIT
2024-06-24 15:02:18(周一) 2024-06-25 00:00:00(星期二) 2024-06-24 00:00:00(周一) 2024-06-25 00:00:00(星期二)
2024-06-25 15:02:18(星期二) 2024-06-26 00:00:00(周三) 2024-06-24 00:00:00(周一) 2024-06-26 00:00:00(周三)
2024-06-26 15:02:18(周三) 2024-06-27 00:00:00 (星期四) 2024-06-24 00:00:00(周一) 2024-06-27 00:00:00 (星期四)
2024-06-27 15:02:18(周四) 2024-06-28 00:00:00(周五) 2024-07-01 00:00:00(周一) 2024-06-28 00:00:00(周五)
2024-06-28 15:02:18(周五) 2024-06-29 00:00:00(周六) 2024-07-01 00:00:00(周一) 2024-06-29 00:00:00(周六)
2024-06-29 15:02:18(周六) 2024-06-30 00:00:00(周日) 2024-07-01 00:00:00(周一) 2024-06-30 00:00:00(周日)
2024-06-30 15:02:18(周日) 2024-07-01 00:00:00(周一) 2024-07-01 00:00:00(周一) 2024-07-01 00:00:00(周一)

由于在欧洲大部分地区,一周的开始是星期一。

如果您在不同的地区使用相同的查询:

ALTER SESSION SET NLS_TERRITORY = 'America'
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS (DY)';
SELECT dt,
       ROUND(dt)        AS default_result,
       ROUND(dt, 'DAY') AS day_explicit,
       ROUND(dt, 'DD') AS dd_explicit
FROM   table_name;
Run Code Online (Sandbox Code Playgroud)

那么输出是:

DT 默认结果 DAY_EXPLICIT DD_EXPLICIT
2024-06-24 15:02:18(周一) 2024-06-25 00:00:00(星期二) 2024-06-23 00:00:00(周日) 2024-06-25 00:00:00(星期二)
2024-06-25 15:02:18(星期二) 2024-06-26 00:00:00(周三) 2024-06-23 00:00:00(周日) 2024-06-26 00:00:00(周三)
2024-06-26 15:02:18(周三) 2024-06-27 00:00:00 (星期四) 2024-06-30 00:00:00(周日) 2024-06-27 00:00:00 (星期四)
2024-06-27 15:02:18(周四) 2024-06-28 00:00:00(周五) 2024-06-30 00:00:00(周日) 2024-06-28 00:00:00(周五)
2024-06-28 15:02:18(周五) 2024-06-29 00:00:00(周六) 2024-06-30 00:00:00(周日) 2024-06-29 00:00:00(周六)
2024-06-29 15:02:18(周六) 2024-06-30 00:00:00(周日) 2024-06-30 00:00:00(周日) 2024-06-30 00:00:00(周日)
2024-06-30 15:02:18(周日) 2024-07-01 00:00:00(周一) 2024-06-30 00:00:00(周日) 2024-07-01 00:00:00(周一)

因为 Oracle 认为美国一周的开始是周日。

如果你这样做:

ALTER SESSION SET NLS_TERRITORY = 'Bangladesh'
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS (DY)';
SELECT dt,
       ROUND(dt)        AS default_result,
       ROUND(dt, 'DAY') AS day_explicit,
       ROUND(dt, 'DD') AS dd_explicit
FROM   table_name;
Run Code Online (Sandbox Code Playgroud)

那么输出是:

DT 默认结果 DAY_EXPLICIT DD_EXPLICIT
2024-06-24 15:02:18(周一) 2024-06-25 00:00:00(星期二) 2024-06-28 00:00:00(周五) 2024-06-25 00:00:00(星期二)
2024-06-25 15:02:18(星期二) 2024-06-26 00:00:00(周三) 2024-06-28 00:00:00(周五) 2024-06-26 00:00:00(周三)
2024-06-26 15:02:18(周三) 2024-06-27 00:00:00 (星期四) 2024-06-28 00:00:00(周五) 2024-06-27 00:00:00 (星期四)
2024-06-27 15:02:18(周四) 2024-06-28 00:00:00(周五) 2024-06-28 00:00:00(周五) 2024-06-28 00:00:00(周五)
2024-06-28 15:02:18(周五) 2024-06-29 00:00:00(周六) 2024-06-28 00:00:00(周五) 2024-06-29 00:00:00(周六)
2024-06-29 15:02:18(周六) 2024-06-30 00:00:00(周日) 2024-06-28 00:00:00(周五) 2024-06-30 00:00:00(周日)
2024-06-30 15:02:18(周日) 2024-07-01 00:00:00(周一) 2024-06-28 00:00:00(周五) 2024-07-01 00:00:00(周一)

在孟加拉国,周五是一周的开始。

同样,如果您将 设为NLS_TERRITORY中东国家,那么您通常会发现一周从星期六开始。

注意:如果您希望始终四舍五入到星期一,请使用IWISO 周开始的格式模型(由 ISO 8601 定义)。

小提琴