2011-07-15 11 views
20

W poniższym przykładzie Pisałem jedną to_str() funkcji i jeden set() procedurę dla każdego pls_integer podtypu. Funkcje i procedury są prawie identyczne, z wyjątkiem typu.Jak wyeliminować zależność podtypów?

Jak mogę wyeliminować potrzebę napisania kolejnego to_str() i set() dla nowego podtypu bez rezygnacji z ograniczeń podanych przez podtyp?

sięgnięcie do varchar2 jak

procedure set(list in varchar2, prefix in varchar2) 

a następnie nazywając go jako

set(to_str(list), 'foos:') 

nie brzmi zbyt wielkiego pojęcia i nadal muszę dostarczyć to_str() dla każdego podtypu.

Jestem otwarty na wszelkiego rodzaju różnych propozycji jak jestem początkującym i nowe Oracle Oracle dysponuje dziwi mnie prawie codziennie.

Używam wersji 11.2.0.1.0.

create table so1table (
    id number, 
    data varchar(20) 
); 

create or replace package so1 as 
    subtype foo_t is pls_integer range 0 .. 4 not null; 
    type foolist is table of foo_t; 
    procedure set(id_ in number, list in foolist default foolist(1)); 

    subtype bar_t is pls_integer range 5 .. 10 not null; 
    type barlist is table of bar_t; 
    procedure set(id_ in number, list in barlist default barlist(5)); 
end; 
/
show errors 

create or replace package body so1 as 
    /* Do I have always to implement these very similar functions/procedures for 
    every single type ? */ 
    function to_str(list in foolist) return varchar2 as 
    str varchar2(32767); 
    begin 
    for i in list.first .. list.last loop 
     str := str || ' ' || list(i); 
    end loop; 
    return str; 
    end; 

    function to_str(list in barlist) return varchar2 as 
    str varchar2(32767); 
    begin 
    for i in list.first .. list.last loop 
     str := str || ' ' || list(i); 
    end loop; 
    return str; 
    end; 

    procedure set(id_ in number, list in foolist default foolist(1)) as 
    values_ constant varchar2(32767) := 'foos:' || to_str(list); 
    begin 
    insert into so1table (id, data) values (id_, values_); 
    end; 

    procedure set(id_ in number, list in barlist default barlist(5)) as 
    values_ constant varchar2(32767) := 'bars:' || to_str(list); 
    begin 
    insert into so1table (id, data) values (id_, values_); 
    end; 
end; 
/
show errors 

begin 
    so1.set(1, so1.foolist(0, 3)); 
    so1.set(2, so1.barlist(5, 7, 10)); 
end; 
/

SQLPLUS> select * from so1table; 

     ID DATA 
---------- -------------------- 
     1 foos: 0 3 
     2 bars: 5 7 10 
+0

Na podstawie odpowiedzi (18 głosów-up, 4 ulubionych i dwóch nie tak precyzyjnych odpowiedzi) do tej pory myślę, że to jest punkt ból PL/SQL i prawdopodobnie nie możliwe z podtypów. Może muszę użyć większego młota: [Używanie PL/SQL z typami obiektów] (http://download.oracle.com/docs/cd/E11882_01/appdev.112/e11822/adobjplsql.htm)? – user272735

Odpowiedz

3
create table so1table (
    id number, 
    data varchar(20) 
); 


create or replace type parent_type as object 
(
    v_number number, 
    --Prefix probably belongs with a list, not an individual value. 
    --For simplicity, I'm not adding another level to the objects. 
    v_prefix varchar2(10) 
) not instantiable not final; 
/

create or replace type parentlist as table of parent_type; 
/


create or replace type foo_type under parent_type 
(
    constructor function foo_type(v_number number) return self as result 
); 
/

--The data must be stored as a NUMBER, since ADTs don't support 
--PL/SQL specific data types. The type safety is enforced by the 
--conversion in the constructor. 
create or replace type body foo_type is 
    constructor function foo_type(v_number number) return self as result 
    as 
     subtype foo_subtype is pls_integer range 0 .. 4 not null; 
     new_number foo_subtype := v_number; 
    begin 
     self.v_number := new_number; 
     self.v_prefix := 'foos:'; 
     return; 
    end; 
end; 
/

create or replace type foolist as table of foo_type; 
/


create or replace type bar_type under parent_type 
(
    constructor function bar_type(v_number number) return self as result 
); 
/

create or replace type body bar_type is 
    constructor function bar_type(v_number number) return self as result 
    as 
     subtype bar_subtype is pls_integer range 5 .. 10 not null; 
     new_number bar_subtype := v_number; 
    begin 
     self.v_number := new_number; 
     self.v_prefix := 'bars:'; 
     return; 
    end; 
end; 
/

create or replace type barlist as table of bar_type; 
/



create or replace package so1 as 
    procedure set(id_ in number, list in parentlist); 
end; 
/

create or replace package body so1 as 

    function to_str(list in parentlist) return varchar2 as 
     v_value VARCHAR2(32767); 
    begin 
     for i in list.first .. list.last loop 
      if i = 1 then 
       v_value := list(i).v_prefix; 
      end if; 
      v_value := v_value || ' ' || list(i).v_number; 
     end loop; 

     return v_value; 
    end to_str; 

    procedure set(id_ in number, list in parentlist) as 
     values_ constant varchar2(32767) := to_str(list); 
    begin 
     insert into so1table (id, data) values (id_, values_); 
    end set; 
end so1; 
/


begin 
    --You probably don't want to mix foos and bars, but it is allowed. 
    so1.set(1, parentlist(foo_type(0), foo_type(3))); 
    so1.set(2, parentlist(bar_type(5), bar_type(7), bar_type(10))); 

    --These would generate "ORA-06502: PL/SQL: numeric or value error" 
    --so1.set(1, parentlist(foo_type(5))); 
    --so1.set(1, parentlist(bar_type(4))); 

end; 
/

select * from so1table; 
+0

Wreszcie odpowiedź, która ma sens. Dzięki !W tej chwili nie podoba mi się, że wszystkie te typy obiektów nie mogą być ukryte w pakiecie, ale zanieczyszczają przestrzeń nazw użytkownika. Zgaduję, że tak właśnie jest z Oracle. – user272735

1

To może nie odpowiedzieć na to pytanie, ale dlaczego nie umieścić dane w zwykłej tabeli, a następnie złączyć je, jak można pokazać, korzystając z funkcji wm_concat agregacji?

tj

> select * from myTable; 

ID Category Value 
--- --------- ------ 
1 foo  0 
2 foo  3 
3 bar  5 
4 bar  7 
5 bar  10 

> select Category||'s: '||replace(wm_concat(Value),',',' ') Data 
    from  myTable 
    group by Category; 

Data 
------------- 
bars: 5 7 10 
foos: 0 3 

wm_concat jest typu niezależne, więc nie ma potrzeby, aby przeładowywać swoich funkcji. Co więcej, można zastosować inne methods; metoda funkcji analitycznej wygląda dobrze, ale nie mam 11g do przetestowania!

(Edit Inaczej myślę można osiągnąć to, czego szukasz za pomocą modelu obiektowego Oracle;. Polimorfizm konkretnie to jednak poza mną ... więc może ktoś inny może kurant.)

-1

Poniższa odpowiedź jest rzeczywiście, jak chcesz to zrobić w PostgreSQL (i plpgsql), a ja też nie wiem o podtypów Oracle, ale zakładam, że są one na tyle podobne, że przynajmniej doprowadzi Cię do odpowiedzi .

create function add (anynonarray,anynonarray) returning anynonarray 
as 'begin return $1 + $2; end'; 

Wiem, że spartaczyłem składnię, ale w każdym razie powinien pokazać to, co chcę z nią pokazać.

Chodzi o to, że zastąpi "anynonarray" or any of the alternatives z typem parametru połączenia. Jednym z ograniczeń jest to, że wszystkie "anynonarray" w powyższym przykładzie będą tego samego typu.

Dokumentacja, o której mowa to jako polimorfizm.

Powiązane problemy