如何使用变量在动态查询中指定 IN 子句?

发布于 2024-12-28 12:56:13 字数 1027 浏览 0 评论 0原文

在 PL/SQL 中,您可以使用串联指定 IN 运算符的值:

v_sql := 'select field1
from table1
where field2 in (' || v_list || ')';

是否可以使用变量执行相同的操作?

v_sql := 'select field1
from table1
where field2 in (:v_list)'; 

如果是这样,怎么办?

编辑:参考Marcin的答案,我如何从结果表中进行选择?

declare

cursor c_get_csv_as_tables is
select in_list(food_list) food_list
from emp_food
where emp_type = 'PERM';

cursor c_get_food_list (v_food_table varchar2Table)is
select *
from v_food_table;

begin
    for i in c_get_csv_as_tables loop
        for j in c_get_food_list(i.food_list) loop
            dbms_output.put_line(j.element);
        end loop;
    end loop;
end;

我收到以下错误:

ORA-06550: line 10, column 6:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 9, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 15, column 34:
PLS-00364: loop index variable 'J' use is invalid
ORA-06550: line 15, column 13:
PL/SQL: Statement ignored

In PL/SQL, you can specify the values for the IN operator using concatenation:

v_sql := 'select field1
from table1
where field2 in (' || v_list || ')';

Is it possible to do the same using a variable?

v_sql := 'select field1
from table1
where field2 in (:v_list)'; 

If so, how?

EDIT: With reference to Marcin's answer, how do I select from the resultant table?

declare

cursor c_get_csv_as_tables is
select in_list(food_list) food_list
from emp_food
where emp_type = 'PERM';

cursor c_get_food_list (v_food_table varchar2Table)is
select *
from v_food_table;

begin
    for i in c_get_csv_as_tables loop
        for j in c_get_food_list(i.food_list) loop
            dbms_output.put_line(j.element);
        end loop;
    end loop;
end;

I get the following error:

ORA-06550: line 10, column 6:
PL/SQL: ORA-00942: table or view does not exist
ORA-06550: line 9, column 1:
PL/SQL: SQL Statement ignored
ORA-06550: line 15, column 34:
PLS-00364: loop index variable 'J' use is invalid
ORA-06550: line 15, column 13:
PL/SQL: Statement ignored

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

转瞬即逝 2025-01-04 12:56:13

就像在@Sathya链接中一样,您可以绑定vararray(我以@Codo为例):

CREATE OR REPLACE TYPE str_tab_type IS VARRAY(10) OF VARCHAR2(200);
/
DECLARE
  l_str_tab str_tab_type;
  l_count NUMBER;
  v_sql varchar2(3000);
BEGIN
  l_str_tab := str_tab_type();
  l_str_tab.extend(2);
  l_str_tab(1) := 'TABLE';
  l_str_tab(2) := 'INDEX';

  v_sql := 'SELECT COUNT(*) FROM all_objects WHERE object_type IN (SELECT COLUMN_VALUE FROM TABLE(:v_list))';

  execute immediate v_sql into l_count using l_str_tab;

  dbms_output.put_line(l_count);
END;
/

更新:第一个命令可以替换为:

CREATE OR REPLACE TYPE str_tab_type IS TABLE OF VARCHAR2(200);
    /

然后调用:

l_str_tab.extend(1);

当您添加值时

Like in @Sathya link, you can bind the varray (I took @Codo example):

CREATE OR REPLACE TYPE str_tab_type IS VARRAY(10) OF VARCHAR2(200);
/
DECLARE
  l_str_tab str_tab_type;
  l_count NUMBER;
  v_sql varchar2(3000);
BEGIN
  l_str_tab := str_tab_type();
  l_str_tab.extend(2);
  l_str_tab(1) := 'TABLE';
  l_str_tab(2) := 'INDEX';

  v_sql := 'SELECT COUNT(*) FROM all_objects WHERE object_type IN (SELECT COLUMN_VALUE FROM TABLE(:v_list))';

  execute immediate v_sql into l_count using l_str_tab;

  dbms_output.put_line(l_count);
END;
/

UPDATE: the first command can be replaced with:

CREATE OR REPLACE TYPE str_tab_type IS TABLE OF VARCHAR2(200);
    /

then call:

l_str_tab.extend(1);

when ever you add a value

§普罗旺斯的薰衣草 2025-01-04 12:56:13

不幸的是,您无法绑定这样的列表,但是您可以使用表函数。阅读此内容

这是一个基于您的代码的用法示例:

declare

cursor c_get_csv_as_tables is
select in_list(food_list) food_list
from emp_food
where emp_type = 'PERM';

cursor c_get_food_list (v_food_table varchar2Table)is
select column_value food
from TABLE(v_food_table);

begin
    for i in c_get_csv_as_tables loop
        for j in c_get_food_list(i.food_list) loop
            dbms_output.put_line(j.food);
        end loop;
    end loop;
end;

我在这里使用了 column_value 伪列

Unfortunately you cannot bind a list like this, however you can use a table function. Read this

Here's an example of usage based on your code:

declare

cursor c_get_csv_as_tables is
select in_list(food_list) food_list
from emp_food
where emp_type = 'PERM';

cursor c_get_food_list (v_food_table varchar2Table)is
select column_value food
from TABLE(v_food_table);

begin
    for i in c_get_csv_as_tables loop
        for j in c_get_food_list(i.food_list) loop
            dbms_output.put_line(j.food);
        end loop;
    end loop;
end;

I used here a column_value pseudocolumn

梦罢 2025-01-04 12:56:13

绑定变量可以在带有“in”子句的 Oracle SQL 查询中使用。

10g 即可工作;我不知道其他版本。

绑定变量是 varchar,最多 4000 个字符。

示例:绑定变量包含以逗号分隔的值列表,例如

:bindvar = 1,2,3,4,5

select * from mytable
  where myfield in
    (
      SELECT regexp_substr(:bindvar,'[^,]+', 1, level) items
      FROM dual
      CONNECT BY regexp_substr(:bindvar, '[^,]+', 1, level) is not null
    );

Bind variable can be used in Oracle SQL query with "in" clause.

Works in 10g; I don't know about other versions.

Bind variable is varchar up to 4000 characters.

Example: Bind variable containing comma-separated list of values, e.g.

:bindvar = 1,2,3,4,5

select * from mytable
  where myfield in
    (
      SELECT regexp_substr(:bindvar,'[^,]+', 1, level) items
      FROM dual
      CONNECT BY regexp_substr(:bindvar, '[^,]+', 1, level) is not null
    );
你另情深 2025-01-04 12:56:13

根据@Marcin的回答,你不能这样做,但是,还有一些需要补充的地方,因为你的查询应该实际工作,即运行。

简而言之,您不能对表或列使用绑定变量。不仅如此,绑定变量被假定为字符,因此如果您想要一个数字,则必须使用 to_number(:b1) 等。

这就是您的查询失败的地方。当您传入一个字符串时,Oracle 假定您的整个列表是单个字符串。因此,您正在有效地跑步:

select field1
  from table1
where field2 = v_list

但是您没有理由不能以不同的方式做到这一点。我假设您正在动态创建 v_list,这意味着您所需要做的就是以不同的方式创建此列表。据称,一系列 or 条件与使用 in 没有什么不同:-)。

据称,我的意思是永远不要依赖未经测试的东西。尽管 Tom 在链接中确实说可能存在性能限制,但不能保证它不会比开始时使用 in 更快。最好的办法是对您的查询和他的查询运行跟踪,看看有什么区别(如果有)。

SQL> set serveroutput on
SQL>
SQL> declare
  2
  3    l_string varchar2(32767);
  4    l_count number;
  5
  6  begin
  7
  8      for xx in ( select rownum as rnum, a.*
  9                    from user_tables a
 10                   where rownum < 20 ) loop
 11
 12        if xx.rnum = 1 then
 13          l_string := 'table_name = ''' || xx.table_name || '''';
 14        else
 15          l_string := l_string || ' or table_name = ''' || xx.table_name || '
''';
 16        end if;
 17
 18      end loop;
 19
 20      execute immediate 'select count(*)
 21                           from user_tables
 22                          where ' || l_string
 23                           into l_count
 24                                ;
 25
 26      dbms_output.put_line('count is ' || l_count);
 27
 28  end;
 29  /
count is 19

PL/SQL procedure successfully completed.

As per @Marcin's answer you can't do this, however, there's a fair bit to add to that, as your query should actually work, i.e. run.

Simply put, you cannot use a bind variable for a table or column. Not only that, bind variables they are assumed to be a character, so if you want a number you have to use to_number(:b1) etc.

This is where your query falls down. As you're passing in a string Oracle assumes that your entire list is a single string. Thus you are effectively running:

select field1
  from table1
where field2 = v_list

There is no reason why you can't do this a different way though. I'm going to assume you're dynamically creating v_list, which means that all you need to do is create this list differently. A series of or conditions is, purportedly :-), no different to using an in.

By purportedly, I mean never rely on something that's untested. Although Tom does say in the link that there may be performance constraints there's no guarantee that it wasn't quicker than using in to begin with. The best thing to do is to run the trace on your query and his and see what difference there is, if any.

SQL> set serveroutput on
SQL>
SQL> declare
  2
  3    l_string varchar2(32767);
  4    l_count number;
  5
  6  begin
  7
  8      for xx in ( select rownum as rnum, a.*
  9                    from user_tables a
 10                   where rownum < 20 ) loop
 11
 12        if xx.rnum = 1 then
 13          l_string := 'table_name = ''' || xx.table_name || '''';
 14        else
 15          l_string := l_string || ' or table_name = ''' || xx.table_name || '
''';
 16        end if;
 17
 18      end loop;
 19
 20      execute immediate 'select count(*)
 21                           from user_tables
 22                          where ' || l_string
 23                           into l_count
 24                                ;
 25
 26      dbms_output.put_line('count is ' || l_count);
 27
 28  end;
 29  /
count is 19

PL/SQL procedure successfully completed.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文