動態SQL對日期處理要特別注意

2021-09-02 12:43:23 字數 4157 閱讀 1400

如果一定要是動態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'

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型別

因為這兩次轉換的格式和環境都一樣的,所以可以自動轉來轉去,當然可讀性不是很好

block中用到self要特別注意記憶體洩露問題

self強引用會使引用計數器加1,如果在dismissviewcontroller時,如 self dismissviewcontrolleranimated no completion nil 不呼叫dealloc方法,需要將self 轉為弱引用 weak typeof self selfvc s...

python中處理鍊錶時特別注意引用傳遞的問題

刷題刷到劍指offer第57題 刪除鍊錶 已排序 中重複的結點 時,按照自己的思路做的,發現輸出結果時出現過以下問題 做題思路 鍊錶相當於乙個前後有關係的陣列,於是先把此題當做刪除陣列中重複的元素來思考,立馬想到可以借用python中的字典來統計每個數字出現的頻數 這樣遍歷一次的時間複雜度為o n ...

9 sql 中對日期的處理

1 查詢當天的使用量 select count count from t user where date create time select curdate 2查詢本週 select from t user where yearweek date format create time,y m d ...