select
max
(decode(
mod
(n,
7
),
0
, m,
null
))
日
,
max
(decode(
mod
(n,
7
),
1
, m,
null
))
一
,
max
(decode(
mod
(n,
7
),
2
, m,
null
))
二
,
max
(decode(
mod
(n,
7
),
3
, m,
null
))
三
,
max
(decode(
mod
(n,
7
),
4
, m,
null
))
四
,
max
(decode(
mod
(n,
7
),
5
, m,
null
))
五
,
max
(decode(
mod
(n,
7
),
6
, m,
null
))
六
from
(
select
rownum
m,
rownum
+ to_char(trunc(
sysdate
,
'mm'
),
'd'
) -
2
n
from
dual
connect
by
rownum
< = to_char(last_day(
sysdate
),
'dd'
))
group
by
trunc(n /
7
)
order
by
trunc(n /
7
);
说明:
1、首先通过
connect
by
rownum
< = to_char(last_day(
sysdate
),
'dd'
) 来取出当月的天数序列
2、再用 to_char(trunc(sysdate, 'mm'), 'd')-2 来提取当天是对应星期几
3、通过
decode(
mod
(n,
7
),
0
, m,
null
) 来确定该天打印在星期几的列中,其实mod放到第2步做思路更加清晰
4、通过
group
by
trunc(n /
7
) 来将一个星期内的天数打印到一行中
5、虽然比较简单,而且也没有什么实用价值,不过这个小程序还是有一些闪光点的,比如group by,记录一下
2、用SQL直接取工作日:
with
t
as
(
select
date
'2008-09-01'
s,
date
'2008-09-10'
e
from
dual)
select
s,e,e-s+
1
total_days,
(length(
replace
(rpad(substr(
'0111110'
,to_char(s,
'd'
)),e-s+
1
,
'0111110'
),
'0'
,
''
))) work_days
from
t;
说明:
1、其他没什么好说的,主要就是
(length(
replace
(rpad(substr(
'0111110'
,to_char(s,
'd'
)),e-s+
1
,
'0111110'
),
'0'
,
''
)))
这句了,一层层看一下
2、substr('0111110',to_char(s,'d')) 这句的作用是找出开始日为星期几,并将其后的每一天对应011110,0为休息日,1为工作日
3、rpad(substr('0111110',to_char(s,'d')),e-s+1,'0111110') 将字符串填充的e-s+1的长度,且每个工作日均对应为1,休息日为0
4、replace 的作用是把011111011111011111……中的0都删除,留下1
5、最后用length 统计一下字符串的长度即为工作日的天数
6、这个方法虽然简单,但是有一个很大的问题,就是Oracle的字符串最长只有4000个字符,也就是说,相隔时间大于4000天的,work_days 将恒等于2858而发生错误,所以需要进行进一步的改进
with
t
as
(selectdate'2008-09-01' s,date'2008-09-10' e from dual
)
select
s,e,e-s+
1
total_days,
trunc((e-s+
1
)/
7
)*
5
+ nvl(length(
replace
(substr(
'01111100111110'
,to_char(s,
'd'
),
mod
(e-s+
1
,
7
)),
'0'
,
''
)),
0
) work_days
from
t;
说明:
1、使用了trunc((e-s+1)/7)*5的形式,然后进行不整位的补足,就没有了字符串长度的限制
2、当(e-s+1)是7的倍数时,显然工作日就是 ((e-s+1)/7)*5
3、当(e-s+1)不被7整除是,可以理解为将最前面不能被7整除的部分mod(e-s+1,7)取出来,剩余的部分则正好为((e-s+1)/7)*5
4、nvl(length(replace(substr('01111100111110',to_char(s,'d'),mod(e-s+1,7)),'0','')),0)就是对mod(e-s+1,7)部分的操作
5、接下来这部分跟前一种方法的原理差不多,就是根据起始位置是星期几,来顺次往后取到工作日标记为1,休息日标记为0
6、需要注意的是substr('0111110',n,0)结果为null,replace('0','0','')的结果也为null,此时整个修正不为结果为null,无法正确显示结果,好在这两种情况下后面部分的结果都是可以忽略不记的,所以在最外面套一层nvl就可以了。