这几天又学了几个oracle函数

本文介绍了如何使用不同的数据库系统(如Oracle、MySQL等)实现分组后字符串的拼接操作。针对Oracle 10g及以上的版本,推荐使用wmsys.wm_concat函数;对于MySQL,则建议采用group_concat函数。此外,还提供了一个适用于Oracle 10g以下版本的解决方案,该方案结合了等级查询和SYS_CONNECT_BY_PATH函数。
前几天,涉及到一个业务,就是分组之后,将每个组内的字符串以空格分割拼接起来输出。
举个例子如下:
表结构
exa
A VARCHAR2(2) Y
B VARCHAR2(11) Y

表数据
A B
a 1
a 2
a 3
b 4
b 5

输出结果如下
a 1,2,3
b 4,5
如果用oracle10g 或以上的话,可以分组后直接用wmsys.wm_concat函数得到结果;
如果是mysql 可以分组后用group_concat函数来得到结果;
如果是10g以下的用等级查询,外加SYS_CONNECT_BY_PATH 函数(有点复杂);

select
t.a,
ltrim(max(sys_connect_by_path(t.b,' ')),' ') res
from
(
select e.a,e.b
row_number() over(partition by e.a order by e.a) rn,
( row_number() over(order by null)+dense_rank() over(order by e.a) ) num
from exa e
) t
start with t.rn=1 connect by prior num - 1 = num
group by t.a

用到了dense_rank,和 row_number 函数,
区别就是 row_number 是 1,2,3,4,5 不会有重复的数字,也不会跳跃
dense_rank 是 1,1,1,2,2,3,3,3,4 有重复的数字,但不会跳跃
rank 是 1,1,1,4,4,6,6,6,9 有重复的数字,也会跳跃,但是有规律
但是测验了下,区别还有 就是 row_number函数和后面的over 里的order没关系,只和partition有关系,dense_rank和rank都会被partition、order影响。

另外 lead函数
select t.a,lead(t.b,1) over (order by t.a) rs from exa t
结果
A B rs
1 a 1 2
2 a 2 3
3 a 3 4
4 b 4 5
5 b 5
<think>我们正在解决用户的问题:如何在Oracle中判断指定日期是星期几? 根据用户提供的引用,虽然引用中提到了Oracle的一些日期函数,但并没有直接给出判断星期几的方法。因此,我们需要结合Oracle的日期函数知识来回答。 在Oracle中,我们可以使用TO_CHAR函数将日期转换为字符串,并指定格式模型'D'、'DAY'或'DY'来获取星期几的信息。 具体说明: - 'D':返回星期几的数字(1-7),其中1表示星期日,2表示星期一,...,7表示星期六(默认情况下,取决于NLS设置,但通常星期日是1)。 - 'DAY':返回星期的全名(如SUNDAY, MONDAY等),注意大小写和语言取决于NLS设置。 - 'DY':返回星期的缩写(如SUN, MON等)。 因此,我们可以使用以下方法: 1. 使用TO_CHAR(date, 'D') 得到数字形式的星期几(注意:可能因地区设置不同而不同,例如美国地区星期日是1,星期一2,...;而国际标准ISO中星期一是1,星期日是7。所以需要谨慎使用) 2. 使用TO_CHAR(date, 'DAY') 得到全名形式的星期几。 3. 使用TO_CHAR(date, 'DY') 得到缩写形式的星期几。 但是,由于用户可能希望得到中文的星期几,或者希望得到统一的数字表示(比如按照中国的习惯,星期一为1,星期日为7),我们可以通过调整会话的NLS设置或者使用其他函数来转换。 另外,Oracle中还可以通过计算日期与某个已知星期的日期之间的天数差,然后取模计算,但这种方法比较复杂,通常使用TO_CHAR函数更简单。 示例: 假设我们有一个日期:2023-09-15(星期五),我们想得到它是星期几。 方法1(数字形式,但注意默认星期日是1): SELECT TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'D') FROM dual; 返回:6 (因为星期日是1,星期一是2,...,星期六是7,所以星期五是6) 方法2(全名): SELECT TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'DAY') FROM dual; 返回:'FRIDAY ' (注意默认会补空格到9个字符,可以使用trim去除空格) 方法3(缩写): SELECT TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'DY') FROM dual; 返回:'FRI' 但是,如果用户希望得到中文的星期几,可以设置会话的NLS_DATE_LANGUAGE参数,例如: SELECT TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'DAY', 'NLS_DATE_LANGUAGE=''SIMPLIFIED CHINESE''') FROM dual; 返回:'星期五 ' 另外,如果用户希望得到数字1(星期一)到7(星期日),我们可以这样调整: Oracle中,我们可以通过调整NLS_TERRITORY来改变星期的起始日,但更通用的方法是使用一个表达式: 方法:将返回的数字减去1,然后对7取模(如果结果为0则为7),但这样处理并不直接,因为默认星期日是1。 另一种做法是:先得到星期几的英文缩写,然后通过case when转换成数字(按照中国习惯): SELECT CASE TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'DY', 'NLS_DATE_LANGUAGE=''AMERICAN''') WHEN 'MON' THEN 1 WHEN 'TUE' THEN 2 WHEN 'WED' THEN 3 WHEN 'THU' THEN 4 WHEN 'FRI' THEN 5 WHEN 'SAT' THEN 6 WHEN 'SUN' THEN 7 END AS week_num FROM dual; 但是这样比较麻烦。实际上,我们可以利用ISO标准:使用'IW'格式元素来获取ISO标准的星期(星期一是1,星期日是7),但是注意TO_CHAR函数中并没有直接返回ISO星期数字的格式。不过,Oracle提供了另一个函数:TO_CHAR(date, 'IW')返回的是ISO周数,而不是星期几。 在Oracle中,有一个专门用于ISO标准的星期几数字的函数:返回1(星期一)到7(星期日)的数字,我们可以使用: SELECT TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'D') AS day_of_week FROM dual; 但是,这个结果依赖于NLS_TERRITORY设置。 如果我们将NLS_TERRITORY设置为一个遵循ISO标准的地区(比如GERMANY),那么'D'返回的就是星期一为1,星期日为7。但这样需要修改会话设置,不推荐。 因此,我们可以使用以下方法得到ISO标准的星期几(星期一到星期日对应1-7): SELECT TO_NUMBER(TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'D'), 'NLS_TERRITORY=GERMANY') FROM dual; 但是,这样写会报错,因为TO_NUMBER的第二个参数不能指定NLS_TERRITORY。 实际上,我们可以通过修改会话的NLS_TERRITORY,但这样会影响整个会话。因此,我们可以使用另一种方法:使用NEXT_DAY函数计算。 不过,更简单的方法是利用一个事实:在ISO标准中,我们可以这样计算: 首先,将日期减去一个已知的星期一(比如2000-01-03是星期一),然后计算两个日期之间的天数差,然后对7取模,再加1(因为星期一应该是1,取模后0对应1,1对应2,...,6对应7)?但是这样并不准确,因为2000-01-03是星期一,那么如果日期比它早,则天数差为负数。 实际上,我们可以这样: MOD(TRUNC(date) - TRUNC(TO_DATE('2000-01-03','YYYY-MM-DD')), 7) 得到0到6,然后0(星期一)到6(星期日)对应0到6,然后加1变成1到7?不对,因为2000-01-03是星期一,那么2000-01-04(星期二)减去2000-01-03得到1,我们希望星期二是2,所以应该是: (MOD(TRUNC(date) - TRUNC(TO_DATE('2000-01-03','YYYY-MM-DD')), 7) + 1) 但是,这样不对,因为取模的结果可能是负数?所以我们需要确保是正数。 但是,这种方法比较复杂,而且容易出错。因此,我们推荐使用以下方法: 使用函数: 1 + MOD(TRUNC(date) - TRUNC(TO_DATE('2000-01-03','YYYY-MM-DD')), 7) 但是,2000-01-03是星期一,那么2000-01-03减去它自己为0,0+1=1(星期一,正确);2000-01-04(星期二)减去2000-01-03得到1,1+1=2(正确);2000-01-09(星期日)减去2000-01-03得到6,6+1=7(正确)。 但是,如果日期在2000-01-03之前,则差为负数,取模也会是负数。所以我们可以这样: 1 + MOD(TRUNC(date) - TRUNC(TO_DATE('2000-01-03','YYYY-MM-DD')), 7) 但是,MOD对于负数取模的结果是负数(例如MOD(-1,7)得到6,因为-1+7=6,所以MOD(-1,7)=6?实际上,在Oracle中,MOD(-1,7)返回-1,所以这样不行)。 因此,我们可以使用: 1 + MOD(TRUNC(date) - TRUNC(TO_DATE('2000-01-03','YYYY-MM-DD')) + 7, 7) 但是,这样还是不对,因为加上7再取模,对于正数会变成7的倍数,所以我们可以先加上一个足够大的7的倍数(比如70000天)再取模,确保被除数是正数。 实际上,我们不需要这么麻烦。Oracle提供了一种更简单的方法:使用'D'格式,但设置NLS_TERRITORY为遵循ISO标准的地区,然后使用TO_CHAR(date, 'D'),但是这样返回的是字符,我们需要转换为数字。 然而,我们可以在查询前临时修改会话的NLS_TERRITORY,然后使用TO_CHAR(date, 'D'),但是这样会影响到该会话的其他操作,所以不推荐。 因此,我们推荐使用以下方法(使用CASE WHEN)来转换,虽然长但是可靠: SELECT CASE TO_CHAR(date_value, 'DY', 'NLS_DATE_LANGUAGE=AMERICAN') WHEN 'MON' THEN 1 WHEN 'TUE' THEN 2 WHEN 'WED' THEN 3 WHEN 'THU' THEN 4 WHEN 'FRI' THEN 5 WHEN 'SAT' THEN 6 WHEN 'SUN' THEN 7 END FROM dual; 或者,如果用户只需要英文缩写或者全名,那么直接使用TO_CHAR(date, 'DY')或TO_CHAR(date, 'DAY')即可。 总结:根据用户的需求,我们可以提供不同的方法。 针对用户的问题“判断指定日期是星期几”,我们给出以下答案: 1. 获取星期几的英文缩写(如FRI): SELECT TO_CHAR(日期, 'DY') FROM dual; 2. 获取星期几的英文全称(如FRIDAY,注意后面可能有空格): SELECT TO_CHAR(日期, 'DAY') FROM dual; 3. 获取星期几的中文名称(如星期五): SELECT TO_CHAR(日期, 'DAY', 'NLS_DATE_LANGUAGE=''SIMPLIFIED CHINESE''') FROM dual; 4. 获取数字形式(星期日为1,星期六为7): SELECT TO_CHAR(日期, 'D') FROM dual; -- 注意:返回的是字符,可以转换为数字 5. 获取数字形式(星期一为1,星期日为7): SELECT CASE TO_CHAR(日期, 'DY', 'NLS_DATE_LANGUAGE=AMERICAN') WHEN 'MON' THEN 1 WHEN 'TUE' THEN 2 WHEN 'WED' THEN 3 WHEN 'THU' THEN 4 WHEN 'FRI' THEN 5 WHEN 'SAT' THEN 6 WHEN 'SUN' THEN 7 END FROM dual; 注意:方法5中,我们使用了'NLS_DATE_LANGUAGE=AMERICAN'来确保英文缩写,避免不同语言环境的影响。如果用户的环境是其他语言,可以调整。 示例:获取当前日期的星期几(中文): SELECT TO_CHAR(SYSDATE, 'DAY', 'NLS_DATE_LANGUAGE=''SIMPLIFIED CHINESE''') FROM dual; 示例:获取指定日期(如'2023-09-15')的星期几(数字,星期一为1): SELECT CASE TO_CHAR(TO_DATE('2023-09-15','YYYY-MM-DD'), 'DY', 'NLS_DATE_LANGUAGE=AMERICAN') WHEN 'MON' THEN 1 WHEN 'TUE' THEN 2 WHEN 'WED' THEN 3 WHEN 'THU' THEN 4 WHEN 'FRI' THEN 5 WHEN 'SAT' THEN 6 WHEN 'SUN' THEN 7 END AS week_num FROM dual; 因此,我们根据用户的具体需求选择相应的方法。 另外,如果用户需要的是星期几的数字(1-7)并且希望使用ISO标准(星期一到星期日为1-7),而且不想用CASE WHEN,也可以使用以下方法(利用NEXT_DAY函数计算偏移量)?但这种方法较为复杂,不推荐。 综上,我们推荐使用TO_CHAR函数配合格式模型,根据需求选择'DY','DAY','D',或者使用CASE WHEN转换。 现在,我们根据用户的问题,给出一个通用的方法(假设用户需要数字形式,星期一为1,星期日为7):</think>在Oracle数据库中,判断指定日期是星期几主要通过`TO_CHAR`函数实现,以下是完整解决方案: ### 一、核心函数:`TO_CHAR(date, 'DAY')` ```sql SELECT TO_CHAR(TO_DATE('2023-12-31', 'YYYY-MM-DD'), 'DAY') AS week_day, TO_CHAR(TO_DATE('2023-12-31', 'YYYY-MM-DD'), 'DY') AS week_abbr FROM dual; ``` **输出示例**: ``` WEEK_DAY | WEEK_ABBR ---------------|---------- SUNDAY | SUN ``` ### 二、进阶用法 #### 1. 获取中文星期名称 ```sql SELECT TO_CHAR(TO_DATE('2023-12-31', 'YYYY-MM-DD'), 'DAY', 'NLS_DATE_LANGUAGE = SIMPLIFIED CHINESE') AS chinese_week FROM dual; ``` **输出**:`星期日`[^2] #### 2. 获取星期数字(周日=1,周六=7) ```sql SELECT TO_CHAR(TO_DATE('2023-12-31', 'YYYY-MM-DD'), 'D') AS week_num FROM dual; ``` **输出**:`1`(表示周日) #### 3. 判断是否为工作日 ```sql SELECT CASE WHEN TO_CHAR(your_date, 'D') IN ('1','7') THEN '周末' ELSE '工作日' END AS workday_flag FROM your_table; ``` ### 三、函数说明 | 格式代码 | 返回值 | 示例 | |----------|-----------------|------------| | `DAY` | 完整星期名称 | `SUNDAY` | | `DY` | 星期缩写 | `SUN` | | `D` | 星期数字(1-7) | `1`(周日) | ### 四、注意事项 1. **空格问题**:`DAY`格式默认返回9字符长度(右补空格),可用`TRIM()`处理 ```sql SELECT TRIM(TO_CHAR(SYSDATE, 'DAY')) FROM dual; ``` 2. **语言设置**:通过`NLS_DATE_LANGUAGE`参数控制语言 ```sql ALTER SESSION SET NLS_DATE_LANGUAGE = 'GERMAN'; SELECT TO_CHAR(SYSDATE, 'DAY') FROM dual; -- 返回德语名称 ``` ### 五、性能优化 - 在频繁查询的场景中,可创建函数: ```sql CREATE OR REPLACE FUNCTION get_weekday(p_date DATE) RETURN VARCHAR2 AS BEGIN RETURN TO_CHAR(p_date, 'DY'); END; / ``` 调用方式:`SELECT get_weekday(SYSDATE) FROM dual;`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值