Попробуйте:
select * from emp order by trunc(hire_date) - trunc(hire_date, 'IW')
Это работает путем вычисления количества дней, прошедших с начала недели (начиная с понедельника).Он вернет 0
для понедельника и 6
для воскресенья.
Почему это работает
trunc(hire_date) - trunc(hire_date, 'IW')
Это все в документации Спецификаторы формата даты Oracle :
IW
: календарная неделя года (1-52 или 1-53), как определено стандартом ISO 8601. В понедельник начинается календарная неделя .
Поскольку этот спецификатор опирается на стандарт ISO, на него не влияют настройки NLS сеанса, в котором он вызывается (см. Подробнее оосложнений этого избежать).Это делает этот подход полностью переносимым (и все же довольно эффективным, поскольку он состоит всего из двух преобразований).
Проблема с TO_CHAR
подходом
Oracle предоставляет функцию TO_CHAR()
, которую можно использовать со спецификатором формата D
для возврата дня недели.Как задокументировано, этот элемент зависит от территории NLS сеанса .
В NLS_TERRITORY
документации написано:
NLS_TERRITORY
задает название территории, правила которой должны соблюдаться для нумерации дней и недель.
По умолчанию этот параметр сеанса инициализируется по умолчанию для сервера.Таким образом, чтобы использовать спецификатор D
в переносимом режиме, вам необходимо сначала изменить настройки сеанса.
Но учтите, что этот параметр также контролирует по умолчанию других параметров сеанса (формат даты, десятичный разделитель, символ валюты, ...): его изменение может повлиять на другие запросы, выполняющиеся в том жесессия удивительным образом.
Рассмотрим эту демонстрацию
Сегодня среда, 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
с .,
на ,
: это произошло из-за того, что значение по умолчанию NLS_NUMERIC_CHARACTERS
было неявно изменено (при изменении NLS_TERRITORY
) И никакое значение не было явно для этого набора параметровклиентом.Tricky.
Демонстрация на скрипте БД
Примечание: в отличие от параметра NLS_DATE_LANGUAGE
, Oracle не позволяет передавать NLS_TERRITORY
в качестве третьегоаргумент TO_CHAR
(я полагаю, что это потому, что он контролирует значения по умолчанию других параметров).