これを使用する最良の方法は、DBMS_SQLを使用することです。
SQLステートメントを表す文字列を作成します。バインド変数は引き続き使用します。痛いです。
これは次のようになります(私はこれをコンパイルしていませんが、近いはずです):-
CREATE OR REPLACE FUNCTION find_country( v_name t1.country%TYPE,
v_type t2.type%TYPE) /* Hmm, column called type? */
DECLARE
v_SQL varchar2(2000);
v_select INTEGER; /* "Pointer" to a DBMS_SQL select statement */
v_execute INTEGER;
BEGIN
v_SQL := 'select column from table1 t1, table2 t2 ||
'where t1.id = t2.id';
IF v_name IS NOT NULL THEN
v_SQL := v_SQL || ' AND t1.country = :v_name'
END IF;
IF v_type IS NOT NULL THEN
v_SQL := v_SQL || ' AND t2.type = :v_type';
END IF;
/* Setup Cursor */
v_select := dbms_sql.open_cursor;
dbms_sql.parse( v_select, v_SQL, DBMS_SQL.native);
IF v_name IS NOT NULL THEN
dbms_sql.bind_variable( v_select, ':v_name', v_name );
END IF;
IF v_type IS NOT NULL THEN
dbms_sql.bind_variable( v_select, ':v_type', v_type );
END IF;
DBMS_SQL.DEFINE_COLUMN(v_select, 1, v_column); /* This is what we have selected */
/* Return value from EXECUTE is undefined for a SELECT */
v_execute := DBMS_SQL.EXECUTE( v_select );
IF DBMS_SQL.FETCH_ROWS( v_select ) > 0 THEN
/* A row was found
DBMS_SQL.COLUMN_VALUE( v_select, 1, v_column);
/* Tidy Up */
DBMS_SQL.CLOSE_CURSOR(v_select);
RETURN v_ID_address;
ELSE
DBMS_SQL.CLOSE_CURSOR(v_select);
/* No row */
RETURN NULL;
END IF;
EXCEPTION
WHEN OTHERS THEN
IF DBMS_SQL.IS_open(v_select) THEN
DBMS_SQL.CLOSE_CURSOR(v_select);
END IF;
RAISE;
END;
このアプローチは、SQLをインラインで記述するのに比べて非常に苦痛であるため、列の山がない限り、この構文を使用していくつかの異なるバージョンを記述する方が簡単な場合があります。
FOR r IN (SELECT blah FROM blah WHERE t1 = v_t1) LOOP
func( r.blah );
END LOOP;