【问题标题】:Pass an array to bind variables传递一个数组来绑定变量
【发布时间】:2018-01-25 09:20:11
【问题描述】:

我有一个包含查询的表,例如:

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;

谢谢!

【问题讨论】:

  • 如果您不知道该表需要多少(或哪些)值,您将如何填充该数组?绑定值是否也被传入;或名称;还是他们在其他地方查找(例如queries 中的另一列)?
  • 感谢您的评论。两个表中都有一个 query_id 列(查询中的 PK 和 vars 中的 FK)。这就是我知道哪个 var 属于每个查询的方式。
  • 所以你只传递了一个查询ID,你必须在程序中查找查询文本和相关变量?在您的示例中,第三个绑定变量名称与vars.name 不匹配。他们真的会 - 永远匹配吗? (如果不是......绑定名称是否总是按照他查询的 ID 顺序排列;并且只出现一次?)

标签: oracle plsql oracle11g execute-immediate bind-variables


【解决方案1】:

我认为您不能使用 execute immediate 来执行此操作,因为在编译时未知太多,因此您必须改用 the dbms_sql package

这是一个基于通用查询 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*Plus variableprint 命令演示:

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 块内的游标。

您也可以转换为引用游标,然后在您的过程中从中获取 - 有 a bulk-collect example in the docs - 但同样您需要知道选择列表项的数量和类型才能做到这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    • 2017-04-04
    • 1970-01-01
    • 2016-09-08
    • 1970-01-01
    相关资源
    最近更新 更多