oracle 拼接sql 日期,动态SQL对日期处理注意事项
如果一定要是動態SQL,一定要將日期類型用||拼起來,見下列寫法,紅色的是錯的,下面的才對,兩次類型轉換,但是沒有什么必要
--要么用綁定變量綁定date類型,要么靜態sql,不要兩次轉換,直接拼日期前后不加單引號還會報錯。
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,應該要使用綁定變量,如果綁定變量適合的話
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;
/
--不用設nls_date_format,因為兩次轉換的nls_date_format一樣,直接to_date,因為自動轉換的字符串沒有引號,需要補上引號
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,自動轉為目標類型,但是要補引號
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使用顯示轉為字符串,和上面一樣
'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,那么日期自動根據session日期設置參數轉換為字符串,而字符串連接不自動加引號,所以就變成上面的了,丟失了引號,自動轉換也失效,語句錯誤了,如果你非要那樣做,只能
1. ? ? ? ?將v_date轉為字符串,帶引號的,然后讓其自動轉換,如: ?v_sql:='select count(*) from test where birth='''||v_date||''''; ?當然也可以使用to_date,如
v_sql:='select count(*) from test where birth=to_date('''||v_date||''')';
不需要nls_date_format設置,因為兩次轉換的格式一樣.
也可以顯示轉換,代替oracle自動轉換v_sql:='select count(*) from test where birth='''||to_char(v_date)||'''';
最完整的全部顯示轉換
v_sql:='select count(*) from test where birth=to_date('''||to_char(v_date,'yyyymmdd')||''',''yyyymmdd'')';
2. ? ? ? ?DDL用不了綁定變量,只能使用1的方法,對非DDL,要用綁定變量,解決這個問題,一般起到軟解析效果。
以上是典型的拼湊導致的程序難以編寫而且容易出錯的例子,如果采用綁定變量的方式,以上問題全可迎刃而解。
也說明了一點,綁定變量不光使我們的SQL反復執行的效率更高,在存儲過程的動態SQL里,綁定變量也會使我們減少錯誤的發生,更容易地進行編程(存儲過程的靜態SQL自動綁定,達到軟解析或軟軟解析的效果,當然動態SQL也可能軟或軟軟解析)
不加to_date,發生2次轉換
第1次,v_date是date類型,但是用||運算,變為字符串
第2次,||兩邊加了引號,但是birth是date類型,又把字符串轉為date類型
因為這兩次轉換的格式和環境都一樣的,所以可以自動轉來轉去,當然可讀性不是很好
總結
以上是生活随笔為你收集整理的oracle 拼接sql 日期,动态SQL对日期处理注意事项的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle 授权 传递,Oracle基
- 下一篇: lnmp环境搭建 php7,lnmp环境