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
);
?
說(shuō)明:
1、首先通過(guò)
connect
by
rownum
< = to_char(last_day(
sysdate
),
'dd'
) 來(lái)取出當(dāng)月的天數(shù)序列
2、再用 to_char(trunc(sysdate, 'mm'), 'd')-2 來(lái)提取當(dāng)天是對(duì)應(yīng)星期幾
3、通過(guò)
decode(
mod
(n,
7
),
0
, m,
null
) 來(lái)確定該天打印在星期幾的列中,其實(shí)mod放到第2步做思路更加清晰
4、通過(guò)
group
by
trunc(n /
7
) 來(lái)將一個(gè)星期內(nèi)的天數(shù)打印到一行中
5、雖然比較簡(jiǎn)單,而且也沒(méi)有什么實(shí)用價(jià)值,不過(guò)這個(gè)小程序還是有一些閃光點(diǎn)的,比如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;
?
說(shuō)明:
1、其他沒(méi)什么好說(shuō)的,主要就是
(length(
replace
(rpad(substr(
'0111110'
,to_char(s,
'd'
)),e-s+
1
,
'0111110'
),
'0'
,
''
)))
這句了,一層層看一下
2、substr('0111110',to_char(s,'d')) 這句的作用是找出開(kāi)始日為星期幾,并將其后的每一天對(duì)應(yīng)011110,0為休息日,1為工作日
3、rpad(substr('0111110',to_char(s,'d')),e-s+1,'0111110') 將字符串填充的e-s+1的長(zhǎng)度,且每個(gè)工作日均對(duì)應(yīng)為1,休息日為0
4、replace 的作用是把011111011111011111……中的0都刪除,留下1
5、最后用length 統(tǒng)計(jì)一下字符串的長(zhǎng)度即為工作日的天數(shù)
6、這個(gè)方法雖然簡(jiǎn)單,但是有一個(gè)很大的問(wèn)題,就是Oracle的字符串最長(zhǎng)只有4000個(gè)字符,也就是說(shuō),相隔時(shí)間大于4000天的,work_days 將恒等于2858而發(fā)生錯(cuò)誤,所以需要進(jìn)行進(jìn)一步的改進(jìn)
?
?
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;
?
說(shuō)明:
1、使用了trunc((e-s+1)/7)*5的形式,然后進(jìn)行不整位的補(bǔ)足,就沒(méi)有了字符串長(zhǎng)度的限制
2、當(dāng)(e-s+1)是7的倍數(shù)時(shí),顯然工作日就是 ((e-s+1)/7)*5
3、當(dāng)(e-s+1)不被7整除是,可以理解為將最前面不能被7整除的部分mod(e-s+1,7)取出來(lái),剩余的部分則正好為((e-s+1)/7)*5
4、nvl(length(replace(substr('01111100111110',to_char(s,'d'),mod(e-s+1,7)),'0','')),0)就是對(duì)mod(e-s+1,7)部分的操作
5、接下來(lái)這部分跟前一種方法的原理差不多,就是根據(jù)起始位置是星期幾,來(lái)順次往后取到工作日標(biāo)記為1,休息日標(biāo)記為0
6、需要注意的是substr('0111110',n,0)結(jié)果為null,replace('0','0','')的結(jié)果也為null,此時(shí)整個(gè)修正不為結(jié)果為null,無(wú)法正確顯示結(jié)果,好在這兩種情況下后面部分的結(jié)果都是可以忽略不記的,所以在最外面套一層nvl就可以了。
?