我有一个包含查询的表,例如:
select text from queries;
TEXT
1 select item from items where item_no between :low_item_no and :high_item_no and description <> :irellevant
查询已包含绑定变量的占位符。
值本身存在于变量表中:
select * from vars;
ID NAME VALUE
1 1 low_item_no 100
2 2 high_item_no 300
3 3 irellevant_desc old
我有一个包,它接受查询并执行它
执行即时语句
但是如何绑定这些变量呢?
我不知道我在这样的查询中有多少变量,它不是静态的。
我希望有一种方法可以做这样的事情:
Execute immedaite my_query_str using v_array_of_vars;
直到现在,我不知道有什么方法可以做这样的事情,只有变量列表,例如:
Execute immedaite my_query_str using v_1, v_2, v_3;
谢谢!
我认为你不能用execute immediate
做到这一点,因为在编译时不知道太多,所以你必须使用dbms_sql
包。
下面是一个快速演示,它基于通用查询 ID 获取查询和变量。这假设vars.name
中的值实际上与queries.text
中的绑定变量名称匹配,并且我没有包含针对该问题或其他潜在问题的任何检查或错误处理,也没有处理多个选择列表项或数据类型 - 只是基础知识:
declare
my_query_str queries.text%type;
my_cursor pls_integer;
my_result pls_integer;
my_col_descs dbms_sql.desc_tab2;
my_num_cols pls_integer;
my_item items.item%type;
begin
select text into my_query_str from queries where query_id = 42;
dbms_output.put_line(my_query_str);
-- open cursor
my_cursor := dbms_sql.open_cursor;
-- parse this query
dbms_sql.parse(my_cursor, my_query_str, dbms_sql.native);
-- bind all variables by name; assumes bind variables match vars.name
for r in (select name, value from vars where query_id = 42) loop
dbms_output.put_line('Binding ' || r.name || ' || with <' || r.value ||'>');
dbms_sql.bind_variable(my_cursor, r.name, r.value);
end loop;
my_result := dbms_sql.execute(my_cursor);
dbms_output.put_line('execute got: ' || my_result);
dbms_sql.describe_columns2(my_cursor, my_num_cols, my_col_descs);
dbms_sql.define_column(my_cursor, 1, my_item, 30); -- whatever size matches 'item'
-- fetch and do something with the results
while true loop
my_result := dbms_sql.fetch_rows(my_cursor);
if my_result <= 0 then
exit;
end if;
dbms_sql.column_value(my_cursor, 1, my_item);
dbms_output.put_line('Got item: ' || my_item);
end loop;
dbms_sql.close_cursor(my_cursor);
end;
/
你似乎并不真正需要一个数组;但是如果你愿意,你可以创建一个关联数组作为名称/值对,然后使用该绑定。
这只是一个起点;您可能必须处理返回的未知数量和/或类型的列,但如果是这种情况,有意义地处理它们将是一个挑战。也许您需要将查询结果作为 ref 游标返回,这更简单;使用 SQL*Plusvariable
和print
命令进行演示:
var rc refcursor;
declare
my_query_str queries.text%type;
my_cursor pls_integer;
my_result pls_integer;
begin
select text into my_query_str from queries where query_id = 42;
dbms_output.put_line(my_query_str);
-- open cursor
my_cursor := dbms_sql.open_cursor;
-- parse this query
dbms_sql.parse(my_cursor, my_query_str, dbms_sql.native);
-- bind all variables by name; assumes bind variables match vars.name
for r in (select name, value from vars where query_id = 42) loop
dbms_output.put_line('Binding ' || r.name || ' || with <' || r.value ||'>');
dbms_sql.bind_variable(my_cursor, r.name, r.value);
end loop;
my_result := dbms_sql.execute(my_cursor);
dbms_output.put_line('execute got: ' || my_result);
:rc := dbms_sql.to_refcursor(my_cursor);
end;
/
print rc
请注意,在这种情况下,您不会关闭 PL/SQL 块内的游标。
您也可以转换为 ref 游标,然后在您的过程中从中获取 - 文档中有一个批量收集示例 - 但同样,您需要知道选择列表项的数量和类型才能做到这一点。