oracle 存儲過程 動態sql語句


一、在oracle項目開發中越到問題:

在利用ODP向oracle中插入數據時,如果這樣寫:
  insert into clobTable (id, story) values(1,'....'); 其中story為clob類型
  如果story的長度大於2000字節,直接插入將出現 ORA-01704:文字字符串過長 的錯誤。
解決方案:
      方案一、利用參數
  insert into clobTable (id, story) values(1,:story);
  OracleParameter param = new OracleParameter("story", OracleDbType.Clob);
  param.Direction = ParameterDirection.Input;
  param.Value = str;
  cmd.Parameters.Add(param);

      方案二、利用存儲過程
  這個就不用說了,寫個存儲過程,把參數傳入即可。

二、解決方法

oracle 中,如下操作:

insert into table values(a,3,'一個長文章');

ORA-01704: 文字字符串過長!

雖然在表中已經是clob字段,足夠存儲4G的內容,但是如果存的是特別長的字符串,超過4000就會報錯。

解決方法:

方法一:就寫個存儲過程,然后用參數傳過去就沒問題了。

declare

v_clob clob :='一個長文章';

begin
  insert into table values(a,3,:clob);
 end;

 這樣就可以插進去了,所以我覺得應該是隱式轉換,oracle默認把字符串 轉換成 varchar2 類型,
 而這個字符串的長度,又比4000大 所以會報ora-01704錯誤.

真實環境用的存儲過程:

 CREATE OR REPLACE PROCEDURE "BAI"."LOGMNRTXT" (tab1 in varchar2,scns in number,timestamps in varchar2,seg_owner in varchar2,
table_name in varchar2,session_info in varchar2,sql_redo in clob,ssession in varchar2,serial in varchar2,operation in varchar2) is

 str varchar(1000);
 --注意tab1必須要更改,發現原來的logmnr_contents20140524中的sql_redo為varchar,需要改成clob
begin

  str:= 'insert into '||tab1||' values(:1,:2,:3,:4,:5,:6,:7,:8,:9)';
   execute immediate str using scns,to_date(timestamps,'yyyy-MM-dd hh24:mi:ss'),seg_owner,table_name,session_info,sql_redo,ssession,serial,operation;
end logmnrtxt;
/

 

方法二:很復雜,其實沒必要這么用,主要是為了學習高級的存儲過程寫法

創建存儲過程:
CREATE OR REPLACE PROCEDURE p_In_Clob(pId IN NUMBER,outVar IN VARCHAR2)
IS
  text_Var  CLOB;
  amount_Var  NUMBER;
  offset_Var  NUMBER;
BEGIN
  INSERT INTO test VALUES(pId,empty_clob());
  SELECT text INTO text_var FROM test
    WHERE id=pId;
  amount_var:=LENGTH(outVar);
  offset_var:=1;
  DBMS_LOB.WRITE(text_Var,amount_Var,offset_Var,outVar);
  COMMIT;
END p_In_Clob;

調用存儲過程:
begin
  p_In_Clob(1,'...');
end;

三、oracle 存儲過程使用動態sql

Oracle存儲過程使用動態SQL 有兩種寫法:用 DBMS_SQL 或 execute immediate,建議使用后者。試驗步驟如下:

1. DDL和DML (注意DDL中可以用拼接字符串的方法用來create table或drop table,在DML中,類似於insert則不可以直接用execute immediate中直接拼接的方法,必須用using傳遞參數)

 1     /*** DDL ***/  
 2     begin   
 3         EXECUTE IMMEDIATE 'drop table temp_1';   
 4         EXECUTE IMMEDIATE 'create table temp_1(name varchar2(8))';   
 5     end;  
 6      
 7     /*** DML ***/  
 8     declare   
 9         v_1 varchar2(8);   
10         v_2 varchar2(10);   
11         str varchar2(50);   
12     begin   
13         v_1:='測試人員';   --這里的v_1,v_2可以是直接存儲過程中傳過來的參數
14         v_2:='北京';   
15         str := 'INSERT INTO test (name ,address) VALUES (:1, :2)';   
16         EXECUTE IMMEDIATE str USING v_1, v_2;   
17         commit;   
18     end;  

 

2. 返回單條結果

例1:

 1     declare   
 2         str varchar2(500);   
 3         c_1 varchar2(10);   
 4         r_1 test%rowtype;   
 5     begin   
 6         c_1:='測試人員';   
 7         str:='select * from test where name=:c WHERE ROWNUM=1';   
 8         execute immediate str into r_1 using c_1;   
 9         DBMS_OUTPUT.PUT_LINE(R_1.NAME||R_1.ADDRESS);   
10     end ; 

例2:

 1     declare  
 2         v_col_name varchar2(30) := 'name'; --字段名 name 用變量來表示  
 3         v_user_name  varchar2(30); --用戶名稱  
 4         v_user_age  integer;       --用戶年齡  
 5         v_sql_str  varchar2(500);  --動態 SQL 語句  
 6     begin  
 7         v_sql_str := 'select '||v_col_name||',age from users --字段名后面不能緊隨 into 到變量了  
 8                        where age between :start_age and :end_age and rownum=1'; --兩個命名參數  ,注意拼接的方法
 9           
10         --用 execute immediate 動態執行 SQL 語句  
11         --注意其后的 into 字段值到變量的寫法,還有 using 來代入參數  
12         execute immediate v_sql_str into v_user_name,v_user_age using 18,25;   
13           
14         dbms_output.put_line('第一個符合條件的用戶:'||v_user_name||',年齡:'||v_user_age);  
15     end;  

 

3. 返回結果集

 1     CREATE OR REPLACE package pkg_test as   
 2         /* 定義ref cursor類型   
 3         不加return類型,為弱類型,允許動態sql查詢,   
 4         否則為強類型,無法使用動態sql查詢;   
 5         */   
 6         type myrctype is ref cursor;  
 7      
 8         --函數申明   
 9         function get(intID number) return myrctype;   
10     end pkg_test;   
11     /  
12      
13     CREATE OR REPLACE package body pkg_test as   
14     --函數體   
15         function get(intID number) return myrctype is   
16             rc myrctype; --定義ref cursor變量   
17             sqlstr varchar2(500);   
18         begin   
19             if intID=0 then   
20                 --靜態測試,直接用select語句直接返回結果   
21                 open rc for select id,name,sex,address,postcode,birthday from   
22     student;   
23             else   
24                 --動態sql賦值,用:w_id來申明該變量從外部獲得   
25                 sqlstr := 'select id,name,sex,address,postcode,birthday from student   
26     where id=:w_id';   
27                 --動態測試,用sqlstr字符串返回結果,用using關鍵詞傳遞參數   
28                 open rc for sqlstr using intid;   
29             end if;  
30      
31             return rc;   
32         end get;  
33      
34     end pkg_test;   
35     /  

四、存儲過程一個總結的非常全的博客

http://www.cnblogs.com/chinafine/archive/2010/07/12/1776102.html

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM