简体   繁体   中英

Oracle Stored procedure to insert into a table with a nested table?

A number of answers exist to this question, but I cant get my head around it!

I have a table which contains a nested table:

    CREATE OR REPLACE TYPE town_objtyp AS OBJECT (
          townName   VARCHAR,
          population     NUMBER,
          desc    VARCHAR(20),   
          ) 
        /

    CREATE TYPE town_nestedtyp AS TABLE OF town_objtyp 
        /

    CREATE OR REPLACE TYPE country_objtyp AUTHID CURRENT_USER AS OBJECT (
          countryName              CHAR(5),
          continent            VARCHAR,
          town_nested     town_nestedtyp,
          ) 
        /

CREATE TABLE Country_objtab OF Country_objtyp (  
           PRIMARY KEY (countryName)
           )                                          

           NESTED TABLE town_nested STORE AS town_store (     
             (PRIMARY KEY(NESTED_TABLE_ID, townName))              
             ORGANIZATION INDEX COMPRESS)                                                                     
        / 

So I want to create a stored procedure that will allow a user to populate this table.

If it were not to have the nested table then it would simply be something like this:

CREATE OR REPLACE PROCEDURE Add_Country (O_countryName IN CHAR, O_continent IN CHAR)
AS

BEGIN
    DBMS_OUTPUT.PUT_LINE ('Insert attempted');

    INSERT INTO Country_objtab(countryName, continent) 
    VALUES(O_countryName, O_continent);

    DBMS_OUTPUT.PUT_LINE ('Insert succeeded');

      END;
/

So how can we change this procedure so that the user can enter n number of towns into the nested table at the same time?

Given your current procedure header passing in two strings and no info on towns, this should work for you:

CREATE OR REPLACE PROCEDURE add_country (o_countryname   IN varchar2,
                                         o_continent     IN varchar2)
AS
BEGIN
   DBMS_OUTPUT.put_line ('Insert attempted');

   INSERT INTO country_objtab (countryname, continent)
           VALUES (
                     NEW country_objtyp (o_countryname,
                                         o_continent,
                                         NEW town_nestedtyp ()));

   DBMS_OUTPUT.put_line ('Insert succeeded');
END;

In other words, you need to use the constructor function to take the individual attribute values (parameters) and return an instance of the object type.

"how can we change this procedure so that the user can enter n number of towns into the nested table at the same time?"

The question is, how much of the implementation detail do you want to show to the consumer of your procedure? You could protect them from the object types altogether but that will only allow them to add one town at a time...

CREATE OR REPLACE PACKAGE pkg_country AS
    PROCEDURE add_country (o_countryname   IN varchar2
                        , o_continent     IN varchar2
                        , p_town_name in varchar2
                        , p_town_pop in varchar2 
                        , p_town_descr in varchar2  );
    PROCEDURE add_town (o_countryname   IN varchar2
                        , p_town_name in varchar2
                        , p_town_pop in varchar2 
                        , p_town_descr in varchar2  );                        
END;
/                        
CREATE OR REPLACE PACKAGE BODY pkg_country AS
    PROCEDURE add_country (o_countryname   IN varchar2
                        , o_continent     IN varchar2
                        , p_town_name in varchar2
                        , p_town_pop in varchar2 
                        , p_town_descr in varchar2  )
    IS
    BEGIN
       INSERT INTO country_objtab VALUES 
       ( NEW country_objtyp (o_countryname,
                             o_continent,
                             NEW town_nestedtyp (
                                new town_objtyp(p_town_name , 
                                                 p_town_pop , 
                                                 p_town_descr ) 
                                )
                            )
                        );
    END  add_country;   

    PROCEDURE add_town (o_countryname   IN varchar2
                        , p_town_name in varchar2
                        , p_town_pop in varchar2 
                        , p_town_descr in varchar2  )
    IS
    BEGIN
      insert into the 
            (select t.town_nested  from Country_objtab t
            where t.countryname  = o_countryname) 
       values ( new town_objtyp(p_town_name , 
                                p_town_pop , 
                                p_town_descr ));
        END  add_town;                                     

END pkg_country;
/

To create a country with multiple towns at once, you could change the signature to accept several town objects:

CREATE OR REPLACE PACKAGE pkg_country AS
    PROCEDURE add_country (o_countryname   IN varchar2
                        , o_continent     IN varchar2
                        , p_town_1 in town_objtyp := null
                        , p_town_2 in town_objtyp := null
                        , p_town_3 in town_objtyp := null );
    PROCEDURE add_town (o_countryname   IN varchar2
                        , p_town in town_objtyp  );
END;
/                        
CREATE OR REPLACE PACKAGE BODY pkg_country AS
    PROCEDURE add_country (o_countryname   IN varchar2
                        , o_continent     IN varchar2
                        , p_town_1 in town_objtyp := null
                        , p_town_2 in town_objtyp := null
                        , p_town_3 in town_objtyp := null  )
    IS
        l_towns town_nestedtyp := new town_nestedtyp();
    BEGIN
       if p_town_1 is not null then
           l_towns.extend();
           l_towns(l_towns.count()) := p_town_1;
       end if;
       if p_town_2 is not null then
           l_towns.extend();
           l_towns(l_towns.count()) := p_town_2;
       end if;
       if p_town_3 is not null then
           l_towns.extend();
           l_towns(l_towns.count()) := p_town_3;
       end if;

       INSERT INTO country_objtab VALUES 
       ( NEW country_objtyp (o_countryname,
                             o_continent,
                             l_towns
                            )
                        );
    END  add_country;   

    PROCEDURE add_town (o_countryname   IN varchar2
                        , p_town_name in varchar2
                        , p_town_pop in varchar2 
                        , p_town_descr in varchar2  )
    IS
    BEGIN
      insert into the 
            (select t.town_nested  from Country_objtab t
            where t.countryname  = o_countryname) 
       values ( new town_objtyp(p_town_name , 
                                p_town_pop , 
                                p_town_descr ));

    END  add_town;                                     

END pkg_country;
/

This is obviously a clunky interface and a clunky implementation. Also it imposes an artificial and undesirable limit on how many towns can be included in the first call. So what you should do is outsource the array population to the calling program:

CREATE OR REPLACE PACKAGE pkg_country AS
    PROCEDURE add_country (o_countryname   IN varchar2
                        , o_continent     IN varchar2
                        , p_towns in town_nestedtyp);
    PROCEDURE add_town (o_countryname   IN varchar2
                        , p_town in town_objtyp  );

END;
/                        
CREATE OR REPLACE PACKAGE BODY pkg_country AS
    PROCEDURE add_country (o_countryname   IN varchar2
                        , o_continent     IN varchar2
                        , p_town_1 in town_objtyp := null
                        , p_town_2 in town_objtyp := null
                        , p_town_3 in town_objtyp := null  )
    IS
    BEGIN

       INSERT INTO country_objtab VALUES 
       ( NEW country_objtyp (o_countryname,
                             o_continent,
                             p_towns
                            )
                        );
    END  add_country;   

    PROCEDURE add_town (o_countryname   IN varchar2
                        , p_town_name in varchar2
                        , p_town_pop in varchar2 
                        , p_town_descr in varchar2  )
    IS
    BEGIN
      insert into the 
            (select t.town_nested  from Country_objtab t
            where t.countryname  = o_countryname) 
       values ( new town_objtyp(p_town_name , 
                                p_town_pop , 
                                p_town_descr ));

    END  add_town;                                     

END pkg_country;
/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM