oracle游標循環的嵌套


完成批量修改user_tables中的所有表的欄位名(從MS SQL導入過來,發現大小寫問題,造成很多麻煩)
存儲過程見下:

-- Created on 2012/3/14 by FREE
declare
  -- Local variables here
  Cursor tbl_cur is select table_name from user_tables;
  --col_cur Cursor;
  i integer;
  tbl_name varchar2(50);
  col_name varchar2(50);
begin
  -- Test statements here
  for tbl_name in tbl_cur LOOP
      for col_cur in (select COLUMN_NAME from all_tab_columns where table_name=tbl_name.table_name) LOOP
          dbms_output.put_line('alter table '||tbl_name.table_name||' rename column "'||col_cur.column_name||'" to '||col_cur.column_name);
      end LOOP;
  end LOOP;
end; 

(從以下轉載文章中收獲很多,謝謝作者。轉自:http://hi.baidu.com/wang90627/blog/item/394e7d019d57329ce850cd5d.html)
創建存儲過程,需要有CREATE PROCEDURE或CREATE ANY PROCEDURE的系統權限。該權限可由系統管理員授予。創建一個存儲過程的基本語句如下:

CREATE [OR REPLACE] PROCEDURE 存儲過程名

   [(參數[IN|OUT|IN OUT]數據類型…)]

   {AS|IS}

      [說明部分]

   BEGIN

      可執行部分

   [EXCEPTION

      錯誤處理部分]

   END [過程名]

其中:

    可選關鍵字OR REPLACE表示如果存儲過程已經存在,則用新的存儲過程覆蓋,通常用於存儲過程的重建。

    參數部分用於定義多個參數(如果沒有參數,就可以省略)。參數有三種形式:IN、OUT和IN OUT。如果沒有指明參數的形式,則默認為IN。

    關鍵字AS也可以寫成IS,后跟過程的說明部分,可以在此定義過程的局部變量。

    編寫存儲過程可以使用任何文本編輯器或直接在SQL *Plus環境下進行,編寫好的存儲過程必須要在SQL *Plus環境下進行編譯,生成編譯代碼,原代碼和編譯代碼在編譯過程中都會被存入數據庫。編譯成功的存儲過程就可以在Oracle環境下進行調用了。

    一個存儲過程在不需要時可以刪除。刪除存儲過程的人是過程的創建者或者擁有DROP ANY PROCEDURE系統權限的人。刪除存儲過程的語法如下:

DROP PROCEDURE 存儲過程名;

    如果要重新編譯一個存儲過程,則只能是過程的創建者或者擁有ALTER ANY PROCEDURE系統權限的人。語法如下:

ALTER PROCEDURE 存儲過程名 COMPILE;

    執行(或調用)存儲過程的人是過程的創建者或是擁有EXECUTE ANY PROCEDURE系統權限的人或是被擁有者授予EXECUTE權限的人。執行的方法如下:

    方法1:

EXECUTE 模式名.存儲過程名[(參數…)];

    方法2:

BEGIN

   模式名.存儲過程名 [(參數…)];

END;

    傳遞的參數必須與定義的參數類型、個數和順序一致(如果參數定義了默認值,則調用時可以省略參數)。參數可以是變量、常量或表達式,用法參見下一節。

    如果是調用本賬戶下的存儲過程,則模式名可以省略。要調用其他賬戶編寫的存儲過程,則模式名必須要添加。



下面是我自己的實驗:

注:游標可以“顯式”聲明,也可以“隱式”聲明。“隱式”聲明的意思是,不用聲明游標,在for循環中直接用游標的record就行。例一是內外 層循環游標都是“隱式”聲明的情況(內層循環的游標,需要用到外層循環的游標值,所以不能兩個游標都在第一個循環外聲明)。(一般:游標名是 xxx__cursor,游標中的每行記錄名是xxx_record 。並且,內層循環要用游標,內層的游標應該要用“隱式”聲明,外層游標可用可不用。)

例一:

CREATE OR REPLACE PROCEDUREmain_mx
           AS
            BEGIN
             FOR mainout_recordIN(  SELECT  /*這里的mainout_record直接是游標的每行記錄了。另外IN后面如果是select語句,就要加括號,並且select語句結束不用;結尾,IN后面如果是游標名,就不要括號*/ ID,smscontent,allcode,cjr,pretongdaoid,clientid,shr,pretime,cjsj,shstatus,shsj

from t_busi_main_presend

where shstatus in('1','9') and klstatus='2') LOOP
             /* insert into T_BUSI_PRESEND_MX*/
                /*  CURSOR mainmobile_cursor IS
                       SELECT  * FROM TABLE(fn_split(mainout_record.allcode,','));  */
                
                    FOR mainmobile_record IN (SELECT  column_value cv FROM TABLE(fn_split(mainout_record.allcode,',')))  LOOP /*SELECT  column_value cv FROM TABLE(fn_split(mainout_record.allcode,','),這句話是執行fn_split這個函數,函數功能類似java中的split功能,但是oracle本身沒有這個函數,所以要自己寫,代碼是我在網上拷的,注意因為mainout_record.allcode這個記錄集就只有“一列”記錄,allcode是外層游標查出來的一個列名,所以前面是selectcolumn_value,后面打印值的時候也是寫.column_value:

功能描述:用指定分隔符切割輸入的字符串,返回一維數組,每個數組元素為一個子串。

先:

CREATE OR REPLACE TYPE ty_str_split IS TABLE OF VARCHAR2 (4000);

再:

CREATE OR REPLACE FUNCTION fn_split(p_str IN CLOB, p_delimiter IN VARCHAR2)
RETURN ty_str_split
IS
  j INT := 0;
  i INT := 1;
  len INT := 0;
  len1 INT := 0;
  str VARCHAR2 (4000);
  str_split ty_str_split := ty_str_split ();
BEGIN
  len := LENGTH (p_str);
  len1 := LENGTH (p_delimiter);

  WHILE j < len
  LOOP
    j := INSTR (p_str, p_delimiter, i);

    IF j = 0
    THEN
        j := len;
        str := SUBSTR (p_str, i);
        str_split.EXTEND;
        str_split (str_split.COUNT) := str;

        IF i >= len
        THEN
          EXIT;
        END IF;
    ELSE
        str := SUBSTR (p_str, i, j - i);
        i := j + len1;
        str_split.EXTEND;
        str_split (str_split.COUNT) := str;
    END IF;
  END LOOP;

  RETURN str_split;
END fn_split;


*/
                         DBMS_OUTPUT.PUT_LINE(mainmobile_record.cv);/*打印結果的時候,直接反鍵存儲過程名-->測試有時是出不來結果的,這時應該"新建"-->"命令窗口"--SQL>set serveroutput on    -->execute main_mx(這是存儲過程名),這樣才能打印結果 */
                      END LOOP;
              END LOOP;    
           END;

例二(外層for循環游標是“顯式”聲明):

CREATE OR REPLACE PROCEDUREmain_mx_1
       as
           CURSOR mainout_cursor IS SELECT ID,smscontent,allcode,cjr,pretongdaoid,clientid,shr,pretime,cjsj,shstatus,shsj from t_busi_main_presend where shstatus in('1','9') and klstatus='2';
            begin
             FOR mainout_record IN  mainout_cursor LOOP
             /*    insert into T_BUSI_PRESEND_MX*/


               /*  CURSOR mainmobile_cursor IS
                       SELECT  * FROM TABLE(fn_split(mainout_record.allcode,','));
                 BEGIN*/
                    FOR mainmobile_record IN (SELECT  column_value cv FROM TABLE(fn_split(mainout_record.allcode,',')))  LOOP
                          DBMS_OUTPUT.PUT_LINE(mainmobile_record.cv);
                      END LOOP;


               END LOOP;

           END; 

 


免責聲明!

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



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