PL / SQL:声明要在IN条件下使用的数字列表

时间:2016-05-25 11:21:08

标签: oracle plsql

是否可以定义将在光标选择中使用的ID列表?

我已尝试按以下方式执行此操作

DECLARE
  insert_user_id number := 1;
  type nt_type is table of number;
  building_num nt_type := nt_type (1,2,3,4,5);

cursor curs1 is
(
  select ID 
  from objects 
  where BUILDING_NUM in (building_num)
);

但我得到的是以下错误:

PLS-00642: local collection types not allowed in SQL statements

我发现,如果我以这种方式声明数字列表,就可以Loop通过它们。但我不想要它。我想要的只是在光标的IN条件内。

我该怎么做?

我想问我,为什么我不把IN中的ID放在光标中?我的回答是:我有几个使用相同列表ID的游标。

修改

根据以下答案,代码如下:

create type nt_type is table of number;

DECLARE
  insert_user_id number := 1;
  building_num nt_type := nt_type (1,2,3,4,5);

cursor curs1(building_nums nt_type) is
(
  select ID 
  from objects 
  where BUILDING_NUM in (select * from table(building_nums))
); 

5 个答案:

答案 0 :(得分:3)

1)Sql只允许使用sql级别的集合。你必须创建它。 create type nt_type is table of number;

2)查询shoull看起来像

DECLARE
  building_num  nt_type  :=  nt_type  (1,2,3,4,5);
begin 
   for rec in (select 1 from dual where 1 member of building_num) loop
     null;
   end loop;
end ;


DECLARE
  building_num  nt_type  :=  nt_type  (1,2,3,4,5);
begin 
   for rec in (select 1 from dual where 1 in (select column_value from table(building_num)) loop
     null;
   end loop;
end ;

此外,您可以检查数据库中是否有现有的号码集合并使用它。select * from ALL_COLL_TYPES where coll_type = 'TABLE' and elem_type_name = 'NUMBER'

答案 1 :(得分:2)

根本问题是SQL查询在SQL上下文中运行,并且无法访问匿名PL / SQL块中定义的私有PL / SQL类型type nt_type is table of number;。相反,你必须使用SQL类型。您将在下面找到如何将数字列表传递给游标的示例。我很肯定你可以根据你的问题调整这个想法!

create table so56_t (
 id number
,d varchar2(1)
);

insert into so56_t values(1, 'A');
insert into so56_t values(2, 'B');
insert into so56_t values(3, 'C');
insert into so56_t values(4, 'D');

-- SQL type required (PL/SQL type won't work)
create type num_list_t is table of number;
/

declare
  cursor cur_c(p_ids num_list_t) is
    select * from so56_t where id in (select* from table(p_ids));
begin
  declare
    v_foos constant num_list_t := num_list_t(1, 3);
    v_bars constant num_list_t := num_list_t(2, 4);

    v_r cur_c%rowtype;
  begin
    open cur_c(v_foos);
    loop
      fetch cur_c into v_r;
      exit when cur_c%notfound;
      dbms_output.put_line(v_r.d);
    end loop;
    close cur_c;

    open cur_c(v_bars);
    loop
      fetch cur_c into v_r;
      exit when cur_c%notfound;
      dbms_output.put_line(v_r.d);
    end loop;
    close cur_c;
  end;
end;
/

运行示例

SQL> /
A
C
B
D

PL/SQL procedure successfully completed.

SQL>

答案 2 :(得分:0)

如果您想使用字符串而不是数字表

DECLARE
  insert_user_id number := 1;
  building_nums varchar2(100) := '1,2,3,4,5';

cursor curs1 is
(
  select ID 
  from objects 
  where BUILDING_NUM  in (    
     SELECT to_number(REGEXP_SUBSTR (building_nums , '[^,]+', 1, LEVEL))
       FROM DUAL
    CONNECT BY REGEXP_SUBSTR (building_nums , '[^,]+', 1, LEVEL) IS NOT NULL
  )
);  

@ArkadiuszŁukasiewicz的变化回答

DECLARE
   insert_user_id   NUMBER := 1;
   -- type nt_type is table of number;
   svar             VARCHAR2 (100) := '1,2,3,4,5';
   building_nums    nt_type;
   n                NUMBER;

   CURSOR curs1
   IS
      (SELECT object_ID
         FROM all_objects
        WHERE object_id IN (SELECT COLUMN_VALUE
                              FROM TABLE (building_nums)));
BEGIN
       SELECT TO_NUMBER (REGEXP_SUBSTR (svar, '[^,]+', 1, LEVEL))
         BULK COLLECT INTO building_nums
         FROM DUAL
   CONNECT BY REGEXP_SUBSTR (svar, '[^,]+', 1, LEVEL) IS NOT NULL;

   OPEN curs1;

   LOOP
      FETCH curs1 INTO n;

      EXIT WHEN curs1%NOTFOUND;
      dbms_output.put_line (n);
   END LOOP;

   CLOSE curs1;
END;

答案 3 :(得分:0)

您可以使用以下查询,将'1,2,3,4,5'替换为必需的值列表或从表中获取。

SELECT REGEXP_SUBSTR(('1,2,3,4,5'),'[^,]+', 1, LEVEL) FROM DUAL CONNECT BY REGEXP_SUBSTR(('1,2,3,4,5'), '[^,]+', 1, LEVEL) IS NOT NULL;

答案 4 :(得分:0)

这与您已经拥有的类似,除了我没有声明游标。我只是想发布它,以免对某人有帮助。

如前所述,首先创建表类型(nt_type)即可根据需要使用它,而不会引发错误:

PLS-00642: local collection types not allowed in SQL statements

话虽如此,这是另一个工作示例...

GIVEN:一个名为OBJECTS的表,其中包含以下数据:

  ID BUILDING_NUM
---- ------------
1000            1
2000            2
3000            3
4000            4
5000            5
6000            6
7000            7
8000            8
9000            9

...和一个名为nt_type的类型

create type nt_type is table of number;

下面的PLSQL遍历OBJECTS表中的ID,其中BUILDING_NUM与给定集合(例如1,2,3,4,5)中的任何ID匹配,并输出一些文本到屏幕上。当然,它可以做一些更有用的事情,例如调用过程或执行一些SQL。

set serveroutput ON

DECLARE
  building_nums nt_type := nt_type (1,2,3,4,5);
BEGIN 
for i in (
   select * from objects 
   where BUILDING_NUM in (select column_value from table(building_nums))
) LOOP
   dbms_output.put_line('--do something with ID: '||i.ID||', matching building_num: '||i.BUILDING_NUM||';');
END LOOP;
END;
/ 

输出:

--do something with ID: 1000, matching building_num: 1;
--do something with ID: 2000, matching building_num: 2;
--do something with ID: 3000, matching building_num: 3;
--do something with ID: 4000, matching building_num: 4;
--do something with ID: 5000, matching building_num: 5;

PL/SQL procedure successfully completed.