Oracle 是否支持非标量游标参数?
Does Oracle support non-scalar cursor parameter?
这是一个关于 Oracle PL/SQL 的问题。
我有一个过程,其中直到 运行 时间才知道确切的 WHERE 子句:
DECLARE
CURSOR my_cursor is
SELECT ...
FROM ...
WHERE terms in (
(SELECT future_term2 FROM term_table), -- whether this element should be included is conditional
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
);
BEGIN
(the processing)
END;
/
什么 (SELECT ... FROM term_table) 查询 returns 是一个 4 个字符的字符串。
为了解决这个问题,我正在考虑使用参数化游标:
DECLARE
target_terms SOME_DATATYPE;
CURSOR my_cursor (pi_terms IN SOME_DATATYPE) IS
SELECT ...
FROM ...
WHERE terms in my_cursor.pi_terms;
BEGIN
target_terms := CASE term_digit
WHEN '2' THEN (
(SELECT future_term2 FROM term_table),
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
) ELSE (
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
)
END;
FOR my_record IN my_cursor (target_terms) LOOP
(the processing)
END LOOP;
END;
/
问题是 SOME_DATATYPE 的数据类型我不知道,也不知道 Oracle 是否支持这样的游标参数。如果支持,上面显示的制造 target_terms 值的方法是否正确?如果没有,怎么办?
希望知道的人指教。非常感谢您的帮助。
您当然可以将参数传递给游标,就像传递给函数一样——但只能传递 IN 参数。但是,PL/SQL是一种强类型语言,所以在编译时必须指定数据类型。
在我看来,您需要做的是动态构建查询,然后使用
OPEN cursor FOR l_query;
其中l_query是构造的字符串。这应该让您了解您可以做什么:
CREATE OR REPLACE PACKAGE return_id_sal
AUTHID DEFINER
IS
TYPE employee_rt IS RECORD
(
employee_id employees.employee_id%TYPE,
salary employees.salary%TYPE
);
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR;
END return_id_sal;
/
CREATE OR REPLACE PACKAGE BODY return_id_sal
IS
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR
IS
l_return SYS_REFCURSOR;
BEGIN
OPEN l_return FOR
'SELECT employee_id, salary FROM employees ' || append_to_from_in;
RETURN l_return;
END allrows_by;
END return_id_sal;
/
DECLARE
l_cursor SYS_REFCURSOR;
l_row return_id_sal.employee_rt;
BEGIN
l_cursor := return_id_sal.allrows_by ('WHERE department_id = 10');
LOOP
FETCH l_cursor INTO l_row;
EXIT WHEN l_cursor%NOTFOUND;
END LOOP;
END;
/
您需要采取预防措施以防止 SQL 注入此类代码。当然,用户永远不能将 SQL 文本直接传递给这样的函数!
您也可以使用一些内置的 VARRAY SQL 类型,例如 SYS.ODCIVARCHAR2LIST
或创建您自己的类型:
CREATE OR REPLACE NONEDITIONABLE TYPE VARCHARLIST
AS VARRAY(32767) OF VARCHAR2(4000);
然后你可以在游标中使用 SELECT COLUMN_VALUE FROM TABLE(COLLECTION)
语句:
DECLARE
l_terms SYS.ODCIVARCHAR2LIS; --or VARCHARLIST
CURSOR my_cursor (p_terms IN SYS.ODCIVARCHAR2LIS) IS
SELECT your_column
FROM your_table
WHERE terms in (select COLUMN_VALUE from table (p_terms));
BEGIN
select term
bulk collect into l_terms
from (
select 'term1' term from dual
union all
select 'term2' term from dual
);
FOR my_record IN my_cursor (l_terms) LOOP
--process data from your cursor...
END LOOP;
END;
这是一个关于 Oracle PL/SQL 的问题。
我有一个过程,其中直到 运行 时间才知道确切的 WHERE 子句:
DECLARE
CURSOR my_cursor is
SELECT ...
FROM ...
WHERE terms in (
(SELECT future_term2 FROM term_table), -- whether this element should be included is conditional
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
);
BEGIN
(the processing)
END;
/
什么 (SELECT ... FROM term_table) 查询 returns 是一个 4 个字符的字符串。
为了解决这个问题,我正在考虑使用参数化游标:
DECLARE
target_terms SOME_DATATYPE;
CURSOR my_cursor (pi_terms IN SOME_DATATYPE) IS
SELECT ...
FROM ...
WHERE terms in my_cursor.pi_terms;
BEGIN
target_terms := CASE term_digit
WHEN '2' THEN (
(SELECT future_term2 FROM term_table),
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
) ELSE (
(SELECT future_term1 FROM term_table),
(SELECT present_term FROM term_table)
)
END;
FOR my_record IN my_cursor (target_terms) LOOP
(the processing)
END LOOP;
END;
/
问题是 SOME_DATATYPE 的数据类型我不知道,也不知道 Oracle 是否支持这样的游标参数。如果支持,上面显示的制造 target_terms 值的方法是否正确?如果没有,怎么办?
希望知道的人指教。非常感谢您的帮助。
您当然可以将参数传递给游标,就像传递给函数一样——但只能传递 IN 参数。但是,PL/SQL是一种强类型语言,所以在编译时必须指定数据类型。
在我看来,您需要做的是动态构建查询,然后使用
OPEN cursor FOR l_query;
其中l_query是构造的字符串。这应该让您了解您可以做什么:
CREATE OR REPLACE PACKAGE return_id_sal
AUTHID DEFINER
IS
TYPE employee_rt IS RECORD
(
employee_id employees.employee_id%TYPE,
salary employees.salary%TYPE
);
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR;
END return_id_sal;
/
CREATE OR REPLACE PACKAGE BODY return_id_sal
IS
FUNCTION allrows_by (append_to_from_in IN VARCHAR2 DEFAULT NULL)
RETURN SYS_REFCURSOR
IS
l_return SYS_REFCURSOR;
BEGIN
OPEN l_return FOR
'SELECT employee_id, salary FROM employees ' || append_to_from_in;
RETURN l_return;
END allrows_by;
END return_id_sal;
/
DECLARE
l_cursor SYS_REFCURSOR;
l_row return_id_sal.employee_rt;
BEGIN
l_cursor := return_id_sal.allrows_by ('WHERE department_id = 10');
LOOP
FETCH l_cursor INTO l_row;
EXIT WHEN l_cursor%NOTFOUND;
END LOOP;
END;
/
您需要采取预防措施以防止 SQL 注入此类代码。当然,用户永远不能将 SQL 文本直接传递给这样的函数!
您也可以使用一些内置的 VARRAY SQL 类型,例如 SYS.ODCIVARCHAR2LIST
或创建您自己的类型:
CREATE OR REPLACE NONEDITIONABLE TYPE VARCHARLIST
AS VARRAY(32767) OF VARCHAR2(4000);
然后你可以在游标中使用 SELECT COLUMN_VALUE FROM TABLE(COLLECTION)
语句:
DECLARE
l_terms SYS.ODCIVARCHAR2LIS; --or VARCHARLIST
CURSOR my_cursor (p_terms IN SYS.ODCIVARCHAR2LIS) IS
SELECT your_column
FROM your_table
WHERE terms in (select COLUMN_VALUE from table (p_terms));
BEGIN
select term
bulk collect into l_terms
from (
select 'term1' term from dual
union all
select 'term2' term from dual
);
FOR my_record IN my_cursor (l_terms) LOOP
--process data from your cursor...
END LOOP;
END;