试试:
select * from emp order by trunc(hire_date) - trunc(hire_date, 'IW')
这是通过计算自一周开始(从星期一开始)以来经过的天数来实现的。它将在星期一返回 0,在星期日返回 6。
为什么会这样
trunc(hire_date) - trunc(hire_date, 'IW')
这一切都在Oracle date format specifiers的文档中:
IW :一年中的日历周(1-52 或 1-53),由 ISO 8601 标准定义。 一个日历周从星期一开始。
由于此说明符依赖于 ISO 标准,因此它不受调用它的会话的 NLS 设置的影响(请参阅有关避免的复杂情况的更多信息)。这使得这种方法完全可移植(并且仍然非常有效,因为它只包含两次转换)。
TO_CHAR 方法的问题
Oracle 提供了TO_CHAR() function,它可以与D 格式说明符一起使用以返回星期几。如文档所述,此元素取决于会话的 NLS 区域。
NLS_TERRITORY documentation 说:
NLS_TERRITORY 指定区域的名称,其日期和星期编号要遵循其惯例。
默认情况下,此会话参数是从服务器的默认值初始化的。因此,要以可移植的方式使用 D 说明符,您需要首先更改会话设置。
但请注意,此参数还控制其他会话参数(日期格式、小数分隔符、货币符号...)的 默认值:修改它可能会影响在同一会话中运行的其他查询令人惊讶的方式。
考虑这个演示
今天是 1 月 28 日星期三,因此是一周的第三天。我们正在创建一个没有指定任何 NLS 参数的新会话,然后:
SELECT parameter, value from v$nls_parameters WHERE parameter = 'NLS_TERRITORY';
PARAMETER | VALUE
:------------ | :------
NLS_TERRITORY | AMERICA
SELECT TO_CHAR(sysdate, 'd') FROM DUAL;
| TO_CHAR(SYSDATE,'D') |
| :------------------- |
| 4 |
当使用服务器的默认区域(美国)时,我们得到了错误的结果:Oracle 认为,在美国,星期从星期日开始。
让我们将参数更改为每周从星期一开始的区域:
ALTER SESSION SET NLS_TERRITORY = 'FRANCE';
SELECT TO_CHAR(sysdate, 'd') FROM DUAL;
| TO_CHAR(SYSDATE,'D') |
| :------------------- |
| 3 |
现在我们得到了我们想要的结果...但是,您应该知道,与此同时,Oracle 将会话参数 NLS_NUMERIC_CHARACTERS 从 ., 更改为 , :这是因为默认值 @987654343 @ 被隐式更改(当NLS_TERRITORY 被更改时)并且客户端没有为该参数设置显式值。棘手。
Demo on DB Fiddle
注意:与NLS_DATE_LANGUAGE 参数不同,Oracle 不允许将NLS_TERRITORY 作为第三个参数传递给TO_CHAR(我想这是因为它控制了其他参数的默认值)。