2016-05-25 12 views
1

Ist es möglich, die Liste der IDs zu definieren, die bei der Cursorauswahl verwendet werden?PL/SQL: Deklarieren Sie die Liste der Nummern, die in der IN-Bedingung verwendet werden sollen

Ich habe versucht, es wie folgt

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

Aber was ich bin immer ist der folgende Fehler zu tun:

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

Was ich herausgefunden habe, ist, dass, wenn ich erklären werde die Liste der Zahlen auf diese Weise wird es möglich sein, Loop durch sie. Aber ich will es nicht. Alles, was ich will, ist innerhalb des IN Zustand des Cursors.

Wie kann ich es tun?

Ich möchte mich fragen, warum ich gerade nicht die IDs innerhalb der IN im Cursor setzen? Meine Antwort ist: Ich habe mehrere Cursor, die die gleichen Listen-IDs verwenden.

EDIT:

Nach Antworten unten sieht der Code wie folgt:

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

Eine mögliche Lösung ist eine Tabelle (oder vielleicht eine temporäre Tabelle) zu erklären, wo Liste von Nummern erforderlich einfügen und dann die Abfrage schreibt Bezugnahme auf die Tabelle – Carlo

Antwort

1

Das eigentliche Problem besteht darin, dass SQL-Abfrage läuft in SQL-Kontext und haben Kein Zugriff auf den privaten PL/SQL-Typ type nt_type is table of number;, der im anonymen PL/SQL-Block definiert ist. Stattdessen müssen Sie den SQL-Typ verwenden. Im Folgenden finden Sie ein Beispiel, wie Sie eine Liste von Zahlen an einen Cursor übergeben können. Ich bin sicher, dass Sie die Idee an Ihr Problem anpassen können!

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

Beispiel Lauf

SQL>/
A 
C 
B 
D 

PL/SQL procedure successfully completed. 

SQL> 
+0

Vielen Dank! Ich habe es gerade geschafft, dein Beispiel anzupassen! – andriy

3

1) Sql nur SQL-Ebene Sammlungen nutzen. Sie müssen es erstellen. create type nt_type is table of number;

2) Und Abfrage shoull aussehen

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 ; 

Auch können Sie Ihre Datenbank überprüfen Sammlung von Nummer für bestehende und nutzen. select * from ALL_COLL_TYPES where coll_type = 'TABLE' and elem_type_name = 'NUMBER'

+0

Ihnen für Ihre Antwort danken, aber es ist nicht genau die Das Gleiche möchte ich umsetzen. Ich werde versuchen, mit anderen Worten zu erklären: Ich möchte eine Variable deklarieren, der ich eine Liste von IDs zuordnen werde. Dann möchte ich wählen mit 'IN' Bedingung. Und in diesem "IN" Zustand möchte ich diese Variable setzen. Mein Ziel ist es, For-Schleifen zu vermeiden. – andriy

+1

@andriy Siehe den Fehler: Lokale Sammlungsarten nicht zulässig. Machen Sie es global, siehe 1) und verwenden Sie dann 2) wo BUILDING_NUM in (wählen Sie column_value aus der Tabelle (Gebäude_num)) – Mottor

0

Wenn Sie Zeichenfolge verwenden und nicht die Tabelle der Nummer

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

und Variation von @Arkadiusz Łukasiewicz beantworten

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

können Sie die unten stehende Abfrage von ‚1,2,3,4,5‘ mit dem erforderlichen Werteliste zu ersetzen oder von Tisch holen.

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