相信很多人都有過統計某些數據的經歷,比如,要統計財務的情況,可能要按每年,每季度,每月,甚至每個星期來分別統計。那在oracle中應該怎么來寫sql語句呢,這個時候Oracle的日期函數會給我們很多幫助。
?常用日期型函數?
1。Sysdate?當前日期和時間
SQL>?Select?sysdate?from?dual;
SYSDATE
----------
21-6月?-05
2。Last_day?本月最后一天?
SQL>?Select?last_day(sysdate)?from?dual;
LAST_DAY(S
----------
30-6月?-05
3。Add_months(d,n)?當前日期d后推n個月?
用于從一個日期值增加或減少一些月份?
date_value:=add_months(date_value,number_of_months)
SQL>?Select?add_months(sysdate,2)?from?dual;
ADD_MONTHS
----------
21-8月?-05
4。Months_between(f,s)?日期f和s間相差月數?
SQL>?select?months_between(sysdate,to_date('2005-11-12','yyyy-mm-dd'))from?dual;
MONTHS_BETWEEN(SYSDATE,TO_DATE('2005-11-12','YYYY-MM-DD'))
----------------------------------------------------------
????????????????????????????????????????????????-4.6966741?
5。NEXT_DAY(d,?day_of_week)
返回由"day_of_week"命名的,在變量"d"指定的日期之后的第一個工作日的日期。參數"day_of_week"必須為該星期中的某一天。
SQL>?SELECT?next_day(to_date('20050620','YYYYMMDD'),1)?FROM?dual;
NEXT_DAY(T
----------
26-6月?-05
6。current_date()返回當前會話時區中的當前日期?
date_value:=current_date?
SQL>?column?sessiontimezone?for?a15?
SQL>?select?sessiontimezone,current_date?from?dual;?
SESSIONTIMEZONE?CURRENT_DA?
---------------?----------?
+08:00??????????13-11月-03?
??
SQL>?alter?session?set?time_zone='-11:00'?2??/?
會話已更改。?
??
SQL>?select?sessiontimezone,current_timestamp?from?dual;?
SESSIONTIMEZONE?CURRENT_TIMESTAMP?
---------------?------------------------------------?
-11:00??????????12-11月-03?04.59.13.668000?下午?-11:00?
7。current_timestamp()以timestamp?with?time?zone數據類型返回當前會話時區中的當前日期
SQL>?select?current_timestamp?from?dual;
CURRENT_TIMESTAMP
---------------------------------------------------------------------------
21-6月?-05?10.13.08.220589?上午?+08:00
8。dbtimezone()返回時區
SQL>?select?dbtimezone?from?dual;
DBTIME
------
-08:00
9。extract()找出日期或間隔值的字段值?
date_value:=extract(date_field?from?[datetime_value|interval_value])?
SQL>?select?extract(month?from?sysdate)?"This?Month"?from?dual;
This?Month
----------
?????????6
SQL>?select?extract(year?from?add_months(sysdate,36))?"?Years"?from?dual;
?????Years
----------
??????2008
10。localtimestamp()返回會話中的日期和時間?
SQL>?select?localtimestamp?from?dual;
LOCALTIMESTAMP
---------------------------------------------------------------------------
21-6月?-05?10.18.15.855652?上午
常用日期數據格式(該段為摘抄)
Y或YY或YYY?年的最后一位,兩位或三位?Select?to_char(sysdate,’YYY’)?from?dual;?002表示2002年?
SYEAR或YEAR?SYEAR使公元前的年份前加一負號?Select?to_char(sysdate,’SYEAR’)?from?dual;?-1112表示公元前111?2年?
Q?季度,1~3月為第一季度?Select?to_char(sysdate,’Q’)?from?dual;?2表示第二季度①?
MM?月份數?Select?to_char(sysdate,’MM’)?from?dual;?12表示12月?
RM?月份的羅馬表示?Select?to_char(sysdate,’RM’)?from?dual;?IV表示4月?
Month?用9個字符長度表示的月份名?Select?to_char(sysdate,’Month’)?from?dual;?May后跟6個空格表示5月?
WW?當年第幾周?Select?to_char(sysdate,’WW’)?from?dual;?24表示2002年6月13日為第24周?
W?本月第幾周?Select?to_char(sysdate,’W’)?from?dual;?2002年10月1日為第1周?
DDD?當年第幾,?1月1日為001,2月1日為032?Select?to_char(sysdate,’DDD’)?from?dual;?363?2002年1?2月2?9日為第363天?
DD?當月第幾天?Select?to_char(sysdate,’DD’)?from?dual;?04?10月4日為第4天?
D?周內第幾天?Select?to_char(sysdate,’D’)?from?dual;?5?2002年3月14日為星期一?
DY?周內第幾天縮寫?Select?to_char(sysdate,’DY’)?from?dual;?SUN?2002年3月24日為星期天?
HH或HH12?12進制小時數?Select?to_char(sysdate,’HH’)?from?dual;?02?午夜2點過8分為02?
HH24?24小時制?Select?to_char(sysdate,’HH24’)?from?dual;?14?下午2點08分為14?
MI?分鐘數(0~59)?Select?to_char(sysdate,’MI’)?from?dual;?17下午4點17分?
SS?秒數(0~59)?Select?to_char(sysdate,’SS’)?from?dual;?22?11點3分22秒?
提示注意不要將MM格式用于分鐘(分鐘應該使用MI)。MM是用于月份的格式,將它用于分鐘也能工作,但結果是錯誤的。?
現在給出一些實踐后的用法:
1。上月末天:
SQL>?select?to_char(add_months(last_day(sysdate),-1),'yyyy-MM-dd')?LastDay?from
dual;
LASTDAY
----------
2005-05-31
2。上月今天
SQL>?select?to_char(add_months(sysdate,-1),'yyyy-MM-dd')?PreToday?from?dual;
PRETODAY
----------
2005-05-21
3.上月首天
SQL>?select?to_char(add_months(last_day(sysdate)+1,-2),'yyyy-MM-dd')?firstDay?from?dual;
FIRSTDAY
----------
2005-05-01
4.按照每周進行統計
SQL>?select?to_char(sysdate,'ww')?from?dual?group?by?to_char(sysdate,'ww');
TO
--
25
5。按照每月進行統計
SQL>?select?to_char(sysdate,'mm')?from?dual?group?by?to_char(sysdate,'mm');
TO
--
06
6。按照每季度進行統計
SQL>?select?to_char(sysdate,'q')?from?dual?group?by?to_char(sysdate,'q');
T
-
2
7。按照每年進行統計
SQL>?select?to_char(sysdate,'yyyy')?from?dual?group?by?to_char(sysdate,'yyyy');
TO_C
----
2005
8.要找到某月中所有周五的具體日期?
select?to_char(t.d,'YY-MM-DD')?from?(?
select?trunc(sysdate,?'MM')+rownum-1?as?d?
from?dba_objects?
where?rownum?<?32)?t?
where?to_char(t.d,?'MM')?=?to_char(sysdate,?'MM')?--找出當前月份的周五的日期?
and?trim(to_char(t.d,?'Day'))?=?'星期五'?
--------?
03-05-02?
03-05-09?
03-05-16?
03-05-23?
03-05-30??
如果把where?to_char(t.d,?'MM')?=?to_char(sysdate,?'MM')改成sysdate-90,即為查找當前月份的前三個月中的每周五的日期。
9.oracle中時間運算
內容如下:?
1、oracle支持對日期進行運算?
2、日期運算時是以天為單位進行的?
3、當需要以分秒等更小的單位算值時,按時間進制進行轉換即可?
4、進行時間進制轉換時注意加括號,否則會出問題?
SQL>?alter?session?set?nls_date_format='yyyy-mm-dd?hh:mi:ss';?
會話已更改。?
SQL>?set?serverout?on?
SQL>?declare?
??2?DateValue?date;?
??3?begin?
??4?select?sysdate?into?DateValue?from?dual;?
??5?dbms_output.put_line('源時間:'||to_char(DateValue));?
??6?dbms_output.put_line('源時間減1天:'||to_char(DateValue-1));?
??7?dbms_output.put_line('源時間減1天1小時:'||to_char(DateValue-1-1/24));?
??8?dbms_output.put_line('源時間減1天1小時1分:'||to_char(DateValue-1-1/24-1/(24*60)));?
??9?dbms_output.put_line('源時間減1天1小時1分1秒:'||to_char(DateValue-1-1/24-1/(24*60)-1/(24*60*60)));?
10?end;?
11?/?
源時間:2003-12-29?11:53:41?
源時間減1天:2003-12-28?11:53:41?
源時間減1天1小時:2003-12-28?10:53:41?
源時間減1天1小時1分:2003-12-28?10:52:41?
源時間減1天1小時1分1秒:2003-12-28?10:52:40?
PL/SQL?過程已成功完成。
在Oracle中實現時間相加處理
--?名稱:Add_Times
--?功能:返回d1與NewTime相加以后的結果,實現時間的相加
--?說明:對于NewTime中的日期不予考慮
--?日期:2004-12-07
--?版本:1.0
--?作者:Kevin
create?or?replace?function?Add_Times(d1?in?date,NewTime?in?date)?return?date?
is
??hh???number;
??mm???number;
??ss???number;
??hours?number;
??dResult??date;??
begin
??--?下面依次取出時、分、秒
??select?to_number(to_char(NewTime,'HH24'))?into?hh?from?dual;
??select?to_number(to_char(NewTime,'MI'))?into?mm?from?dual;
??select?to_number(to_char(NewTime,'SS'))?into?ss?from?dual;
??--?換算出NewTime中小時總和,在一天的百分幾
??hours?:=?(hh?+?(mm?/?60)?+?(ss?/?3600))/?24;
??--?得出時間相加后的結果
??select?d1?+?hours?into?dResult?from?dual;
??return(dResult);
end?Add_Times;
--?測試用例
--?select?Add_Times(sysdate,to_date('2004-12-06?03:23:00','YYYY-MM-DD?HH24:MI:SS'))?from?dual
在Oracle9i中計算時間差
計算時間差是Oracle?DATA數據類型的一個常見問題。Oracle支持日期計算,你可以創建諸如“日期1-日期2”這樣的表達式來計算這兩個日期之間的時間差。?
???
??
一旦你發現了時間差異,你可以使用簡單的技巧來以天、小時、分鐘或者秒為單位來計算時間差。為了得到數據差,你必須選擇合適的時間度量單位,這樣就可以進行數據格式隱藏。?
??
使用完善復雜的轉換函數來轉換日期是一個誘惑,但是你會發現這不是最好的解決方法。?
??
round(to_number(end-date-start_date))-?消逝的時間(以天為單位)?
??
round(to_number(end-date-start_date)*24)-?消逝的時間(以小時為單位)?
??
round(to_number(end-date-start_date)*1440)-?消逝的時間(以分鐘為單位)?
??
顯示時間差的默認模式是什么?為了找到這個問題的答案,讓我們進行一個簡單的SQL?*Plus查詢。?
??
SQL>?select?sysdate-(sysdate-3)?from?dual;?
??
SYSDATE-(SYSDATE-3)?
-------------------?
???????????????????3??
??
這里,我們看到了Oracle使用天來作為消逝時間的單位,所以我們可以很容易的使用轉換函數來把它轉換成小時或者分鐘。然而,當分鐘數不是一個整數時,我們就會遇到放置小數點的問題。?
??
Select?
????(sysdate-(sysdate-3.111))*1440?
from?
????dual;?
??
(SYSDATE-(SYSDATE-3.111))*1440?
------------------------------?
?????????????????????4479.83333??
??
當然,我們可以用ROUND函數(即取整函數)來解決這個問題,但是要記住我們必須首先把DATE數據類型轉換成NUMBER數據類型。?
??
Select?
????round(to_number(sysdate-(sysdate-3.111))*1440)?
from?
????dual;?
??
ROUND(TO_NUMBER(SYSDATE-(SYSDATE-3.111))*1440)?
----------------------------------------------?
???????????????????????????????????????????4480??
??
我們可以用這些函數把一個消逝時間近似轉換成分鐘并把這個值寫入Oracle表格中。在這個例子里,我們有一個離線(logoff)系統級觸發機制來計算已經開始的會話時間并把它放入一個Oracle?STATSPACK?USER_LOG擴展表格之中。?
??
Update?
????perfstat.stats$user_log?
set?
????elapsed_minutes?=?
????round(to_number(logoff_time-logon_time)*1440)?
where?
????user?=?user_id?
and?
????elapsed_minutes?is?NULL;?
查出任一年月所含的工作日
CREATE?OR?REPLACE?FUNCTION?Get_WorkingDays(
??ny?IN?VARCHAR2
)?RETURN?INTEGER?IS
/*------------------------------------------------------------------------------------------
函數名稱:Get_WorkingDays
中文名稱:求某一年月中共有多少工作日
作者姓名:?XINGPING
編寫時間:?2004-05-22
輸入參數:NY:所求包含工作日數的年月,格式為yyyymm,如200405
返?回?值:整型值,包含的工作日數目。
算法描述:
????1).列舉出參數給出的年月中的每一天。這里使用了一個表(ljrq是我的庫中的一張表。這個表可以是有權訪問的、記錄條數至少為31的任意一張表或視圖)來構造出某年月的每一天。
????2).用這些日期和一個已知星期幾的日期相減(2001-12-30是星期天),所得的差再對7求模。如果所求年月在2001-12-30以前,那么所得的差既是負數,求模后所得值范圍為大于-6,小于0,如-1表示星期六,故先將求模的結果加7,再求7的模.
????3).過濾掉結果集中值為0和6的元素,然后求count,所得即為工作日數目。??????
-------------------------------------------------------------------------------------------------*/
??Result?INTEGER;
BEGIN
??SELECT?COUNT(*)?INTO?Result
????FROM?(SELECT?MOD(MOD(q.rq-to_date('2001-12-30','yyyy-mm-dd'),7),7)?weekday
????????????FROM?(?SELECT?to_date(ny||t.dd,'yyyymmdd')?rq
?????????????????????FROM?(SELECT?substr(100+ROWNUM,2,2)?dd?
?????????????????????????????FROM?ljrq?z?WHERE?Rownum<=31
??????????????????????????)?t
?????????????????????WHERE?to_date(ny||t.dd,'yyyymmdd')?
???????????????????????BETWEEN?to_date(ny,'yyyymm')?
???????????????????????????AND?last_day(to_date(ny,'yyyymm'))
?????????????????)q
?????????)?a???
????WHERE?a.weekday?NOT?IN(0,6);????
??RETURN?Result;??
END?Get_WorkingDays;
______________________________________
還有一個版本
CREATE?OR?REPLACE?FUNCTION?Get_WorkingDays(
??ny?IN?VARCHAR2
)?RETURN?INTEGER?IS
/*-----------------------------------------------------------------------------------------
函數名稱:Get_WorkingDays
中文名稱:求某一年月中共有多少工作日
作者姓名:?XINGPING
編寫時間:?2004-05-23
輸入參數:NY:所求包含工作日數的年月,格式為yyyymm,如200405
返?回?值:整型值,包含的工作日數目。
算法描述:使用Last_day函數計算出參數所給年月共包含多少天,根據這個值來構造一個循環。在這個循環中先求這個月的每一天與一個已知是星期天的日期(2001-12-30是星期天)的差,所得的差再對7求模。如果所求日期在2001-12-30以前,那么所得的差既是負數,求模后所得值范圍為大于-6,小于0,如-1表示星期六,故先將求模的結果加7,再求7的模.?如過所得值不等于0和6(即不是星期六和星期天),則算一個工作日。??????
----------------------------------------------------------------------------------------*/
??Result?INTEGER?:=?0;
??myts?INTEGER;??????--所給年月的天數
??scts?INTEGER;??????--某天距2001-12-30所差的天數
??rq???DATE;
??djt?INTEGER?:=?1;???--?
BEGIN
??myts?:=?to_char(last_day(to_date(ny,'yyyymm')),'dd');??
??LOOP?
????rq?:=?TO_date(ny||substr(100+djt,2),'yyyymmdd');
????scts?:=?rq?-?to_date('2001-12-30','yyyy-mm-dd');
????IF?MOD(MOD(scts,7)+7,7)?NOT?IN(0,6)?THEN
??????Result?:=?Result?+?1;
????END?IF;
????djt?:=?djt?+?1;??
????EXIT?WHEN?djt>myts;
??END?LOOP;??
??RETURN?Result;??
END?Get_WorkingDays;
以上兩個版本的比較
第一個版本一條SQL語句就可以得出結果,不需要編程就可以達到目的。但需要使用任意一張有權訪問的、記錄條數至少為31的一張表或視圖。
????第二個版本需要編程,但不需要表或者視圖。
????這兩個版本都還存在需要完善的地方,即沒有考慮節日,如五一、十一、元旦、春節這些節假期都沒有去除。這些節假日應該維護成一張表,然后通過查表來去除這些節假日。