使用 Oracle SQL,如何创建以下结果集:
例如:
日期名称 1 星期一 2 星期二 3 周三 4 星期四 5 周五 6 星期六 7 周日
Florin 的答案是我会如何做,但你需要小心 NLS 设置。一周中的哪一天受到 NLS 区域的影响,所以如果我像在美国一样运行它,它会起作用:
alter session set nls_territory = 'AMERICA';
select to_char(sysdate, 'D') as d, to_char(sysdate, 'Day') as day from dual;
D DAY
- ------------------------------------
6 Friday
select level as dow,
to_char(trunc(sysdate ,'D') + level, 'Day') as day
from dual
connect by level <= 7;
DOW DAY
--- ------------------------------------
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
7 Sunday
但是在英国运行的相同查询是休息日:
alter session set nls_territory = 'UNITED KINGDOM';
select to_char(sysdate, 'D') as d, to_char(sysdate, 'Day') as day from dual;
D DAY
- ------------------------------------
5 Friday
select level as dow,
to_char(trunc(sysdate ,'D') + level, 'Day') as day
from dual
connect by level <= 7;
DOW DAY
--- ------------------------------------
1 Tuesday
2 Wednesday
3 Thursday
4 Friday
5 Saturday
6 Sunday
7 Monday
...我需要调整计算来纠正这一点:
select level as dow,
to_char(trunc(sysdate ,'D') + level - 1, 'Day') as day
from dual
connect by level <= 7;
DOW DAY
--- ------------------------------------
1 Monday
2 Tuesday
3 Wednesday
4 Thursday
5 Friday
6 Saturday
7 Sunday
如果需要,您还可以单独指定日期名称所使用的语言:
select level as dow,
to_char(trunc(sysdate ,'day') + level - 1, 'Day',
'NLS_DATE_LANGUAGE=FRENCH') as day
from dual
connect by level <= 7;
DOW DAY
--- --------------------------------
1 Lundi
2 Mardi
3 Mercredi
4 Jeudi
5 Vendredi
6 Samedi
7 Dimanche
to_char()
以及 nls_date_language
和星期几的文档,以及全球化支持指南中的更多信息。
尝试从日期获取天数时,您可以避免使用
NLS_TERRITORY
时 TO_CHAR(dt, 'D')
设置引发的问题,而是将这一天与 ISO 周的开始时间(始终是星期一午夜)进行比较:
SELECT TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW') + 1 AS day_number,
TO_CHAR(SYSDATE, 'fmDAY') AS day
FROM DUAL;
哪个输出:
DAY_NUMBER 白天 5 周五
注意:您还可以使用
fmDAY
自动删除日期名称中的尾随空格。如果您使用 DAY
(不带 fm
修饰符),则所有日期名称将被填充为相等的长度;对于英语来说,这意味着 Friday
将被右填充到与 Wednesday
相同的长度。
使用 ISO 周与使用
TO_CHAR
进行比较:
ALTER SESSION SET NLS_TERRITORY = 'GERMANY';
SELECT TO_CHAR(SYSDATE, 'D') AS dn_tochar
TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW') + 1 AS dn_isoweek
FROM DUAL
输出:
DN_TOCHAR DN_ISOWEEK 5 5
哪个好;由于 Oracle 认为德国的一周从星期一开始,因此星期五是一周的第五天。
但是在不同的地区进行相同的查询:
ALTER SESSION SET NLS_TERRITORY = 'BANGLADESH';
SELECT TO_CHAR(SYSDATE, 'D') AS dn_tochar
TRUNC(SYSDATE) - TRUNC(SYSDATE, 'IW') + 1 AS dn_isoweek
FROM DUAL
输出:
DN_TOCHAR DN_ISOWEEK 1 5
并且没有给出与
TO_CHAR
版本相同的答案,因为 Oracle 认为孟加拉国的一周从周五开始,因此这将是一周的第一天。
同样,在其他国家/地区,埃及的一周从周六开始,美国的一周从周日开始,因此如果您使用
TO_CHAR
,它们的所有值都将关闭;但如果你使用 ISO 周则不然。
但是,如果您只想生成一周中的每一天的 7 行,那么您可以简化问题并使用分层查询来生成日期数字,然后从 ISO 周的开始位置偏移日期:
SELECT LEVEL AS day_number,
TO_CHAR(
TRUNC(SYSDATE, 'IW') + LEVEL - 1,
'fmDAY',
'NLS_DATE_LANGUAGE=English'
) AS day
FROM DUAL
CONNECT BY LEVEL <= 7;
始终输出:
DAY_NUMBER 白天 1 周一 2 星期二 3 星期三 4 星期四 5 周五 6 星期六 7 周日
db<>小提琴这里
select level as dow,
to_char(level+trunc(sysdate,'D'),'Day') as day
from dual
connect by level <= 7;
无需更改会话
CASE
WHEN to_char(sysdate, 'd')-1 = 0 THEN 7
ELSE to_char(sysdate, 'd')-1
END
在 Oracle Database 23ai 中,您可以创建一个 枚举域来列出一周中的日子:
create domain days_of_week as enum (
monday, tuesday, wednesday,
thursday, friday, saturday,
sunday
);
select * from days_of_week;
ENUM_NAME ENUM_VALUE
--------- ----------
MONDAY 1
TUESDAY 2
WEDNESDAY 3
THURSDAY 4
FRIDAY 5
SATURDAY 6
SUNDAY 7
值从 1 开始,每一项增加 1。您可以提供自己的起始值。例如,从星期一开始,其值为零:
drop domain if exists days_of_week;
create domain days_of_week as enum (
monday = 0, tuesday, wednesday,
thursday, friday, saturday,
sunday
);
select * from days_of_week;
ENUM_NAME ENUM_VALUE
--------- ----------
MONDAY 0
TUESDAY 1
...
SUNDAY 6
或者您可以使用每一天的字符串值。这里的值是日期名称的两个字母缩写:
drop domain if exists days_of_week;
create domain days_of_week as enum (
monday = 'MO', tuesday = 'TU',
wednesday = 'WE', thursday = 'TH',
friday = 'FR', saturday = 'SA',
sunday = 'SU'
);
select * from days_of_week;
ENUM_NAME EN
--------- --
MONDAY MO
TUESDAY TU
WEDNESDAY WE
THURSDAY TH
FRIDAY FR
SATURDAY SA
SUNDAY SU
您还可以将多个名称与一个值链接起来。内置枚举
day_enum_d
列出了每个名称的全名和三个字母缩写:
select * from sys.day_enum_d;
ENUM_NAME ENUM_VALUE
--------- ----------
MONDAY 1
MON 1
TUESDAY 2
TUE 2
WEDNESDAY 3
...
Select 1, 'Monday' from dual union all select 2, 'Tuesday' from dual ...