Search code examples
oracle-databaseplsqlinsertrowtype

Oracle: Insert rowtype data into another table


I have one table called event, and created another global temp table tmp_event with the same columns and definition with event. Is it possible to insert records in event to tmp_event using this ?

DECLARE
   v_record event%rowtype;
BEGIN 
   Insert into tmp_event values v_record;
END;

There are too many columns in event table, I want to try this because I don't want to list all the columns.

Forget to mention: I will use this in the trigger, can this v_record be the object :new after insert on EVENT table ?


Solution

  • To insert one row-

    DECLARE
       v_record event%rowtype;
    BEGIN 
       SELECT * INTO v_record from event where rownum=1; --or whatever where clause
       Insert into tmp_event values v_record;
    END;
    

    Or a more elaborate version to insert all rows from event-

    DECLARE
      TYPE t_bulk_collect_test_tab IS TABLE OF event%ROWTYPE;
    
      l_tab t_bulk_collect_test_tab;
    
      CURSOR c_data IS
        SELECT *
        FROM event;
    BEGIN
      OPEN c_data;
      LOOP
        FETCH c_data
        BULK COLLECT INTO l_tab LIMIT 10000;
        EXIT WHEN l_tab.count = 0;
    
        -- Process contents of collection here.
        Insert into tmp_event values v_record;
      END LOOP;
      CLOSE c_data;
    END;
    /
    

    In a trigger, yes it is possible but its like the chicken or the egg. You have to initialize every field of the rowtype with the :new column values like-

    v_record.col1 := :new.col1;
    v_record.col2 := :new.col2;
    v_record.col3 := :new.col3;
    ....
    

    Apparently, the PLSQL examples above cannot be used in a trigger since it would throw a mutating trigger error. And there is no other way for you to get the entire row in the trigger other than accessing each column separately as I explain above, so if you do all this why not directly use :new.col in the INSERT into temp_event itself, will save you a lot of work.


    Also since you say it's a lot of work to mention all the columns, (in Oracle 11gR2) here's a quick way of doing that by generating the INSERT statement and executing it dynamically (although not tested for performance).

    CREATE OR REPLACE TRIGGER event_air --air stands for "after insert of row"
    AFTER INSERT ON EVENT
    FOR EACH ROW
       L_query varchar2(2000);   --size it appropriately
    BEGIN
    
       SELECT 'INSERT INTO tmp_event VALUES ('|| listagg (':new.'||column_name, ',') 
                                               WITHIN GROUP (ORDER BY column_name) ||')' 
         INTO l_query
         FROM all_tab_columns
        WHERE table_name='EVENT';
    
       EXECUTE IMMEDIATE l_query;
    
    EXCEPTION
        WHEN OTHERS THEN
            --Meaningful exception handling here
    END;