oracle 拼接sql 日期,动态SQL对日期处理注意事项
如果一定要是動態(tài)SQL,一定要將日期類型用||拼起來,見下列寫法,紅色的是錯的,下面的才對,兩次類型轉(zhuǎn)換,但是沒有什么必要
--要么用綁定變量綁定date類型,要么靜態(tài)sql,不要兩次轉(zhuǎn)換,直接拼日期前后不加單引號還會報錯。
SQL> DECLARE
2 ? v_date date := sysdate;
3 ? v_cnt number := 0;
4 ? v_sql varchar2(100);
5 ?BEGIN
6 ? ?v_sql := 'SELECT COUNT(*) FROM USER_OBJECTS WHERE CREATED<='||v_date;
7 ? ?DBMS_OUTPUT.PUT_LINE(v_sql);
8 ? ?v_sql := 'SELECT COUNT(*) FROM USER_OBJECTS WHERE CREATED<='||chr(39)||v_date||chr(39);
9 ? ? ?DBMS_OUTPUT.PUT_LINE(v_sql);
10 ? ?EXECUTE IMMEDIATE v_sql INTO v_cnt;
11 ? ? ? ?DBMS_OUTPUT.PUT_LINE(v_cnt);
-- v_sql := 'SELECT COUNT(*) FROM USER_OBJECTS WHERE CREATED<=TO_DATE('''||v_date||''',''dd-mon-yy'')';
-- ? DBMS_OUTPUT.PUT_LINE(v_sql);
12 ?END;
13 ?/
SELECT COUNT(*) FROM USER_OBJECTS WHERE CREATED<=04-1月 -11
SELECT COUNT(*) FROM USER_OBJECTS WHERE CREATED<='04-1月 -11'
1810
PL/SQL procedure successfully completed
DROP TABLE t;
CREATE TABLE t(p1 DATE)
PARTITION BY RANGE(p1)
(PARTITION p0 VALUES LESS THAN ?( TO_DATE ('20110816', 'YYYYMMDD')) ?TABLESPACE USERS);
所以:
1.對非DDL,應(yīng)該要使用綁定變量,如果綁定變量適合的話
2.DDL,用不了綁定變量,必須to_date拼湊
DECLARE
p1 ? DATE := TO_DATE ('20110817', 'YYYYMMDD');
BEGIN
EXECUTE IMMEDIATE 'alter session set nls_date_format=''yyyymmdd''';
FOR i IN 1 .. 2
LOOP
EXECUTE IMMEDIATE
'alter table t add partition p'
|| TO_CHAR (p1, 'YYYYMMDD')
|| ' ?VALUES LESS THAN ( TO_DATE('''
|| p1
|| ''',''yyyymmdd'')) ?TABLESPACE USERS';
p1 := p1 + 1;
END LOOP;
END;
/
--不用設(shè)nls_date_format,因為兩次轉(zhuǎn)換的nls_date_format一樣,直接to_date,因為自動轉(zhuǎn)換的字符串沒有引號,需要補上引號
DECLARE
p1 ? DATE := TO_DATE ('20110817', 'YYYYMMDD');
BEGIN
FOR i IN 1 .. 2
LOOP
EXECUTE IMMEDIATE
'alter table t add partition p'
|| TO_CHAR (p1, 'YYYYMMDD')
|| ' ?VALUES LESS THAN ( TO_DATE('''
|| p1
|| ''')) ?TABLESPACE USERS';
p1 := p1 + 1;
END LOOP;
END;
/
--甚至可以去掉to_date,自動轉(zhuǎn)為目標(biāo)類型,但是要補引號
DECLARE
p1 ? DATE := TO_DATE ('20110817', 'YYYYMMDD');
BEGIN
DBMS_OUTPUT.put_line( ? ? 'alter table t add partition p'
|| TO_CHAR (p1, 'YYYYMMDD')
|| ' ?VALUES LESS THAN ( '''
|| p1
|| ''') ?TABLESPACE USERS');
END;
/
也可以對p使用顯示轉(zhuǎn)為字符串,和上面一樣
'alter table t add partition p'
|| TO_CHAR (p1, 'YYYYMMDD')
|| ' ?VALUES LESS THAN ( TO_DATE('''
|| TO_CHAR(p1,'YYYY-MM-DD')
|| ''',''YYYY-MM-DD'')) ?TABLESPACE USERS'
再看一個典型的拼湊日期的錯誤。
我常常看到別人不使用綁定變量,采用拼湊的方式傳入日期類型,比如:
declare
vname varchar2(10):='dd';
v_sql varchar2(4000);
vcnt number;
v_date date:=sysdate;
begin
v_sql:='select count(*) from test where birth='||v_date; --這里要出錯
dbms_output.put_line(v_sql);
execute immediate v_sql into vcnt;
dbms_output.put_line(vcnt);
end;
這里又出什么錯呢?請看打印出的語句是什么?
select count(*) from test where birth=08-5月 -10
原來在運行期,如果采用||date,那么日期自動根據(jù)session日期設(shè)置參數(shù)轉(zhuǎn)換為字符串,而字符串連接不自動加引號,所以就變成上面的了,丟失了引號,自動轉(zhuǎn)換也失效,語句錯誤了,如果你非要那樣做,只能
1. ? ? ? ?將v_date轉(zhuǎn)為字符串,帶引號的,然后讓其自動轉(zhuǎn)換,如: ?v_sql:='select count(*) from test where birth='''||v_date||''''; ?當(dāng)然也可以使用to_date,如
v_sql:='select count(*) from test where birth=to_date('''||v_date||''')';
不需要nls_date_format設(shè)置,因為兩次轉(zhuǎn)換的格式一樣.
也可以顯示轉(zhuǎn)換,代替oracle自動轉(zhuǎn)換v_sql:='select count(*) from test where birth='''||to_char(v_date)||'''';
最完整的全部顯示轉(zhuǎn)換
v_sql:='select count(*) from test where birth=to_date('''||to_char(v_date,'yyyymmdd')||''',''yyyymmdd'')';
2. ? ? ? ?DDL用不了綁定變量,只能使用1的方法,對非DDL,要用綁定變量,解決這個問題,一般起到軟解析效果。
以上是典型的拼湊導(dǎo)致的程序難以編寫而且容易出錯的例子,如果采用綁定變量的方式,以上問題全可迎刃而解。
也說明了一點,綁定變量不光使我們的SQL反復(fù)執(zhí)行的效率更高,在存儲過程的動態(tài)SQL里,綁定變量也會使我們減少錯誤的發(fā)生,更容易地進行編程(存儲過程的靜態(tài)SQL自動綁定,達到軟解析或軟軟解析的效果,當(dāng)然動態(tài)SQL也可能軟或軟軟解析)
不加to_date,發(fā)生2次轉(zhuǎn)換
第1次,v_date是date類型,但是用||運算,變?yōu)樽址?/p>
第2次,||兩邊加了引號,但是birth是date類型,又把字符串轉(zhuǎn)為date類型
因為這兩次轉(zhuǎn)換的格式和環(huán)境都一樣的,所以可以自動轉(zhuǎn)來轉(zhuǎn)去,當(dāng)然可讀性不是很好
總結(jié)
以上是生活随笔為你收集整理的oracle 拼接sql 日期,动态SQL对日期处理注意事项的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 授权 传递,Oracle基
- 下一篇: lnmp环境搭建 php7,lnmp环境