【问题标题】:Using bind variable in 'IN' clause在“IN”子句中使用绑定变量
【发布时间】:2012-11-17 15:03:42
【问题描述】:

我想将一个数字列表查询到一个 plsql 变量中,并在另一个 sql 查询的 in 子句中使用它。我在下面创建了一个我想做的测试用例。

我在谷歌上搜索了解决方案,我认为它一定是可能的,但我就是没有让它运行。请帮助我提供编译解决方案。

CREATE OR REPLACE PROCEDURE PROCEDURE1 
as
  type t_id is table of number;
  v_ids t_id;
  v_user_ids number;
BEGIN

-- fill variable v_id with id's, user_id is of type number
select user_id
bulk collect into v_ids
from user_users;

-- then at a later stage ... issue a query using v_id in the in clause
select user_id into v_user_ids from user_users
-- this line does not compile ( local collection type not allowed in SQL statements)
where user_id in ( v_ids );

END PROCEDURE1;

【问题讨论】:

  • 也许这是一个简化的演示,但如果你给出的情况是你不只是将两个查询合二为一吗? “选择 ... from ... 其中 user_id 在(从 ...中选择 user_id)”?还是执行联接?
  • 是的,这是愚蠢的,可能没有意义。我需要编译示例 - 我在行中收到错误: where user_id in ( v_ids )
  • 使用 sql 数组与 plsql 嵌套表不是您的选择吗?如果是,我们可以使用 TABLE() 函数来解决问题(尽管您的最后一条语句没有意义,因为它是一个选择,所以您最终只有一行?如果您真正的 sql 是 select max () 或 rownum = 1 什么的)。
  • slq 数组:我声明'type t_id is varray(1000) of number;'并使用'where user_id in (table(v_ids));'但这也不编译
  • @user1863377 我的意思是,create type t_id as table of number; 而不是在你的 PLSQL 块中。这可以接受吗?

标签: oracle plsql oracle10g bind-variables


【解决方案1】:

使用 SQL 类型:

SQL> create type t_id is table of number;
  2  /

Type created.

SQL> CREATE OR REPLACE PROCEDURE PROCEDURE1
  2  as
  3    v_ids t_id;
  4    v_user_ids number;
  5  BEGIN
  6
  7    -- fill variable v_id with id's, user_id is of type number
  8    select user_id
  9    bulk collect into v_ids
 10    from user_users
 11    where user_id between 100 and 120;
 12
 13    select user_id into v_user_ids
 14      from user_users
 15     where user_id in (select /*+ cardinality(t, 10) */ t.column_value from table(v_ids) t)
 16       and rownum = 1;
 17
 18    dbms_output.put_line(v_user_ids);
 19
 20  END PROCEDURE1;
 21  /

Procedure created.

SQL> exec procedure1
100

cardinality(t, 10) 应该是对数组中有多少元素的合理猜测。

注意: 像你一样使用无限制的批量收集:

  8    select user_id
  9    bulk collect into v_ids
 10    from user_users;

如果您的数组最终可以包含数千行或更多行,则通常不是很好,因为您对内存施加了太大压力并最终会使代码崩溃。最好使用显式游标open x for .. 和在循环中使用限制子句进行批量提取,即fetch x bulk collect into v_ids limit 100,并以100-1000 的批量处理。

【讨论】:

  • 这很好,内部选择可以解决问题!我可以避免create type ... 吗?是否可以重用 oracle 已经提供的类型? - 真正的代码确实会通过 1000 批中的 1 亿条记录。我是一个 java 人,出于性能原因需要在 plsql 中执行此操作。
  • 你可以检查一下你的数据库select owner, type_name, coll_type, upper_bound, precision, scale from all_coll_types where elem_type_name = 'NUMBER'; 中有什么可用的,然后选择一个(例如v_ids KU$_OBJNUMSET;)。请记住,通过使用 Oracle 拥有的 (SYS),它的主题会在 Oracle 的未来版本中消失或更改 :)
  • “1,000 批次”和“性能”对我来说是相互排斥的。如果您确实有大量记录,请考虑将需要传递给代码的值插入到全局临时表中并加入其中,使用尽可能少的 SQL 语句。
  • @DavidAldridge 如果您可以将其作为 1 个 sql 执行,则为真,那么更好,但如果不能,则有限制的批量收集比循环更好,并且比没有限制更安全。
猜你喜欢
  • 2011-06-25
  • 2014-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-10
  • 1970-01-01
  • 2021-04-26
  • 1970-01-01
相关资源
最近更新 更多