2016-05-25 46 views
1

是否可以定义将在光标选择中使用的id列表?PL/SQL:声明IN条件中要使用的数字列表

我试着做如下

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)) 
); 
+0

一个可能的解决方案是声明,其中插入所需数量的名单表(或者一个临时表),然后编写查询参照表 – Carlo

回答

1

问题的根源是,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> 
+0

谢谢!我只是设法调整你的例子! – andriy

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'

+0

谢谢你的答案,但它是不完全的同样的事情,我想实施。我将尝试用另一个词来解释:我想声明一个变量,我将为其赋予一个ID列表。然后我想用'IN'条件做选择。在这个'IN'条件下,我想把这个变量。我的目标是避免循环。 – andriy

+1

@andriy查看错误:不允许LOCAL集合类型。使其成为全局的,请参阅1),然后使用2)其中BUILDING_NUM在(从表(building_num)中选择column_value) – Mottor

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卢卡西维奇变化表回答

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; 
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;