2016-05-25 50 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;