我遇到了Oracle 23c的奇怪行为.据我所知,舍入函数中缺少第二个参数与显式设置‘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
  ;

根据Oracle documentation"如果省略fmt,则日期将四舍五入为最接近的日期",而‘day’参数仅表示日期.

The result looks like this -> Shouldn't day_explicit column be like 2024-06-27? enter image description here

推荐答案

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

ROUND(date_value, 'DD')是四舍五入到最接近的日子.

这一点记录在ROUND and TRUNC Date Functions documentation:

Format Model Rounding or Truncating Unit
DDD
DD
J
Day
DAY
DY
D
Starting day of the week

例如:

如果您有样例数据:

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;

并且您可以使用:

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;

则输出为:

DT DEFAULT_RESULT DAY_EXPLICIT DD_EXPLICIT
2024-06-24 15:02:18 (MON) 2024-06-25 00:00:00 (TUE) 2024-06-24 00:00:00 (MON) 2024-06-25 00:00:00 (TUE)
2024-06-25 15:02:18 (TUE) 2024-06-26 00:00:00 (WED) 2024-06-24 00:00:00 (MON) 2024-06-26 00:00:00 (WED)
2024-06-26 15:02:18 (WED) 2024-06-27 00:00:00 (THU) 2024-06-24 00:00:00 (MON) 2024-06-27 00:00:00 (THU)
2024-06-27 15:02:18 (THU) 2024-06-28 00:00:00 (FRI) 2024-07-01 00:00:00 (MON) 2024-06-28 00:00:00 (FRI)
2024-06-28 15:02:18 (FRI) 2024-06-29 00:00:00 (SAT) 2024-07-01 00:00:00 (MON) 2024-06-29 00:00:00 (SAT)
2024-06-29 15:02:18 (SAT) 2024-06-30 00:00:00 (SUN) 2024-07-01 00:00:00 (MON) 2024-06-30 00:00:00 (SUN)
2024-06-30 15:02:18 (SUN) 2024-07-01 00:00:00 (MON) 2024-07-01 00:00:00 (MON) 2024-07-01 00:00:00 (MON)

因为在欧洲大部分地区,一周的开始是星期一.

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

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;

则输出为:

DT DEFAULT_RESULT DAY_EXPLICIT DD_EXPLICIT
2024-06-24 15:02:18 (MON) 2024-06-25 00:00:00 (TUE) 2024-06-23 00:00:00 (SUN) 2024-06-25 00:00:00 (TUE)
2024-06-25 15:02:18 (TUE) 2024-06-26 00:00:00 (WED) 2024-06-23 00:00:00 (SUN) 2024-06-26 00:00:00 (WED)
2024-06-26 15:02:18 (WED) 2024-06-27 00:00:00 (THU) 2024-06-30 00:00:00 (SUN) 2024-06-27 00:00:00 (THU)
2024-06-27 15:02:18 (THU) 2024-06-28 00:00:00 (FRI) 2024-06-30 00:00:00 (SUN) 2024-06-28 00:00:00 (FRI)
2024-06-28 15:02:18 (FRI) 2024-06-29 00:00:00 (SAT) 2024-06-30 00:00:00 (SUN) 2024-06-29 00:00:00 (SAT)
2024-06-29 15:02:18 (SAT) 2024-06-30 00:00:00 (SUN) 2024-06-30 00:00:00 (SUN) 2024-06-30 00:00:00 (SUN)
2024-06-30 15:02:18 (SUN) 2024-07-01 00:00:00 (MON) 2024-06-30 00:00:00 (SUN) 2024-07-01 00:00:00 (MON)

因为甲骨文认为美国一周的开始是周日.

如果您这样做了:

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;

则输出为:

DT DEFAULT_RESULT DAY_EXPLICIT DD_EXPLICIT
2024-06-24 15:02:18 (MON) 2024-06-25 00:00:00 (TUE) 2024-06-28 00:00:00 (FRI) 2024-06-25 00:00:00 (TUE)
2024-06-25 15:02:18 (TUE) 2024-06-26 00:00:00 (WED) 2024-06-28 00:00:00 (FRI) 2024-06-26 00:00:00 (WED)
2024-06-26 15:02:18 (WED) 2024-06-27 00:00:00 (THU) 2024-06-28 00:00:00 (FRI) 2024-06-27 00:00:00 (THU)
2024-06-27 15:02:18 (THU) 2024-06-28 00:00:00 (FRI) 2024-06-28 00:00:00 (FRI) 2024-06-28 00:00:00 (FRI)
2024-06-28 15:02:18 (FRI) 2024-06-29 00:00:00 (SAT) 2024-06-28 00:00:00 (FRI) 2024-06-29 00:00:00 (SAT)
2024-06-29 15:02:18 (SAT) 2024-06-30 00:00:00 (SUN) 2024-06-28 00:00:00 (FRI) 2024-06-30 00:00:00 (SUN)
2024-06-30 15:02:18 (SUN) 2024-07-01 00:00:00 (MON) 2024-06-28 00:00:00 (FRI) 2024-07-01 00:00:00 (MON)

因为孟加拉的这周是星期五开始.

同样,如果你把NLS_TERRITORY设定为中东的一个国家,你会发现这一周大多是从周六开始的.

Note: If you want to always round to Monday then use the 100 format model for the start of the ISO week (as defined by ISO 8601).

fiddle

Sql相关问答推荐

在SQL:2003(PGQ)中,Cypher查询语言、GQL、PGQL和属性图查询的常见子集是什么?'

使用SQL/R循环查找邻居

用于匹配红旗和绿旗的SQL查询

使用`lag()`获取上一个时间戳

在甲骨文中查找前一个星期一的S日期

返回包含列和包含其他列的列表的自定义查询

从依赖于其他表的值的XREF表中的值分组获得正确的计数?

如何从查询中的三个或更多个表中添加另一个相同的列?

为什么SQL in中的空子查询有时被视为null

将具有嵌套 XML 的列转换为 SQL 中的表格格式?

获取上个月和上一年的值

SQL:考虑合并分支计算分支的增长百分比

oracle中多行的跨日期范围的交集

在 SQL 中使用循环遍历按时间顺序排列的数据

SQL - 只需要 GROUP BY SELECT 的一列

计算 PostgreSQL 中的平均会话长度

如何从 2 个 SQLite 表构建嵌套对象?

Postgres 条件求和函数

将单行中的多个行值转换为列

从不同的表中 Select 包含单词列表的记录