動態SQL中使用Open for語句
Open for本是為了支援遊標變數,現在用它實現多行動態查詢。OPEN FOR的語法如下:
OPEN{cursor_variable | :host_cursor_viable}FOR SQL_string
[USING bind_argument [, bind_argument]…];
解釋:
Cursor_variable是一種弱型別的遊標變數。
:host_cursor_variable是在PL/SQL宿主環境下宣告的遊標變數,如Oracle呼叫介面程式。
SQL_string包含動態執行的SELECT語句。
USING子句與EXECUTE IMMEDIATE語句遵循相同的規則。
使用OPEN FOR語句開啟動態查詢的例子:
PROCEDURE show_parts_inventory(
parts_table IN VARCHAR2, where_in IN VARCHAR2)
IS
TYPE query_curtype IS REF CURSOR;
dyncur query_curtype;
BEGIN
OPEN dyncur FOR
'SELECT * FROM' || parts_table || 'WHERE' || where_in;
。。。
執行OPEN FOR語句時,PL/SQL執行引擎操作如下:
1、 將遊標變數與在查詢字串找到的查詢相關聯。
2、 對繫結引數求值,並用這些值替換查詢字串內的佔位符。
3、 執行查詢。
4、 識別結果集。
5、 將遊標放在結果集第一行。
6、 把由%ROWCOUNT返回的行計數值歸零。
注意,查詢中任何繫結引數(由USING子句提供),僅當遊標變數開啟時才能求值。這意味著如果我們想對相同的動態查詢使用不同的繫結引數值,
就必須使用該引數再執行一次OPEN FOR語句。
執行多行查詢需遵循以下步驟:
1、 宣告一個REFCURSOR型別(或使用Oracle定義的SYS_REFCURSOR弱CURSOR型別)。
2、 基於這個REF CURSOR型別宣告一個遊標變數。
3、 用這個遊標變數開啟查詢字串。
4、 使用FETCH語句提供查詢確認的一行或多行結果集。
5、 必要時檢查遊標屬性(%FOUND、%NOTFOUND、%ROWCOUNT、%ISOPEN)。
6、 使用標準CLOSE語句關閉遊標變數。
/*顯示任何一個表中由WHERE子句所選出的行的指定列的內容(對數字、日期和字串列有效)*/
/*引數說明:tab:表名、col:列名、whr:條件*/
PROCEDURE showcol(tab IN VARCHAR2,
col IN Varchar2,
whr IN VARCHAR2:=NULL)
IS
cv SYS_REFCURSOR;
val VARCHAR2(32767);
BEGIN
OPEN cv FOR
--注意字串之間的空格
'SELECT ' || col ||
' FROM ' || tab ||
' WHERE ' || NVL(whr, '1 = 1');
LOOP
--取cv的值給val,如果找不到就退出,和顯示遊標相同
FETCH cv INTO val;
EXIT WHEN cv%NOTFOUND;
--如果取到第一行,顯示頭部的資訊
IFcv%ROWCOUNT = 1
THEN
Dbms_Output.put_line(RPAD('_',60,'_'));
Dbms_Output.put_line(
'Contents of ' || UPPER(tab)|| '.' || UPPER(col));
Dbms_Output.put_line(RPAD('_',60,'_'));
END IF;
Dbms_Output.put_line(val);
END LOOP;
--記得關閉遊標
CLOSE cv;
END;
/*升級版showcol程式,顯示帶有一個時間列,並且時間列在一定範圍數值內的所有列的資訊*/
PROCEDURE showcol(tab VARCHAR2,
col VARCHAR2,
dtcol VARCHAR2,
dt1 DATE,
dt2 DATE := NULL)
IS
cvSYS_REFCURSOR;
val VARCHAR2(32767);
BEGIN
OPEN cv FOR
--注意空格
'SELECT ' || col ||
' FROM ' || tab ||
' WHERE ' || dtcol ||
' BETWEEN TRUNC (:startdt) AND TRUNC (:enddt)'
USING dt1, NVL (dt2, dt1+1);
LOOP
--取cv的值給val,如果找不到就退出
FETCH cv INTO val;
EXIT WHEN cv%NOTFOUND;
--如果取到第一行,顯示資訊
IF cv%ROWCOUNT = 1
THEN
Dbms_Output.put_line(
'Contents of ' || UPPER(tab)|| '.' || UPPER(col) ||
' for ' || UPPER(dtcol) ||
' between ' || dt1 || ' AND' || NVL (dt2, dt1+1));
END IF;
Dbms_Output.put_line(val);
ENDLOOP;
CLOSE cv;
END;