Home > Enterprise >  SQL Oracle object%rowtype dynamic
SQL Oracle object%rowtype dynamic

Time:07-22

I have an object which is a ROWTYPE from a table and need to recover some of the columns to an array list.

For example:

The ROWTYPE contents Name1, Last_Name1, Id1, Adress1...Name25,Last_Name25,Id25,Adress25 in columns.

I need to know if I can recover them by a dynamic way with a loop to an array type like this:

Name(1-25),Last_Name(1-25),Id(1-25),Adress(1-25).

CodePudding user response:

Given a simplified example of the problem with the table:

CREATE TABLE table_name (id1, name1, id2, name2, id3, name3, id4, name4) AS
SELECT 1, 'N1', 2, 'N2', 3, 'N3', 4, 'N4' FROM DUAL;

I am assuming, that to get the %ROWTYPE variable, you are using something like:

DECLARE
  data TABLE_NAME%ROWTYPE;
BEGIN
  SELECT * INTO data FROM table_name FETCH FIRST ROW ONLY;

  DBMS_OUTPUT.PUT_LINE('1: ' || data.id1 || ', ' || data.name1);
  DBMS_OUTPUT.PUT_LINE('2: ' || data.id2 || ', ' || data.name2);
  DBMS_OUTPUT.PUT_LINE('3: ' || data.id3 || ', ' || data.name3);
  DBMS_OUTPUT.PUT_LINE('4: ' || data.id4 || ', ' || data.name4);
END;
/

Rather than trying to dynamically access the %ROWTYPE record, why do you not bypass the problem and separate the values in the SELECT statement using UNPIVOT in a cursor and then you can use %ROWTYPE on the cursor (rather than the table):

DECLARE
  CURSOR cur IS
    SELECT id, name
    FROM   (SELECT * FROM table_name FETCH FIRST ROW ONLY)
    UNPIVOT (
      (id, name)
      FOR idx IN (
        (id1, name1) AS 1,
        (id2, name2) AS 2,
        (id3, name3) AS 3,
        (id4, name4) AS 4
      )
    );
  
  TYPE cur_row_arr IS TABLE OF cur%ROWTYPE;
  rw  cur%ROWTYPE;
  arr cur_row_arr := cur_row_arr();
BEGIN
  OPEN cur;
  LOOP
    FETCH cur INTO rw;
    EXIT WHEN cur%NOTFOUND;
    arr.EXTEND;
    arr(arr.COUNT) := rw;
  END LOOP;
  CLOSE cur;
  
  FOR i IN 1 .. arr.COUNT LOOP
    DBMS_OUTPUT.PUT_LINE( i || ': ' || arr(i).id || ', ' || arr(i).name );
  END LOOP;
END;
/

db<>fiddle here

CodePudding user response:

Don't try to do it dynamically, just hard-code the values.

Given the simplified example:

CREATE TABLE table_name (id1, name1, id2, name2, id3, name3, id4, name4) AS
SELECT 1, 'N1', 2, 'N2', 3, 'N3', 4, 'N4' FROM DUAL;

Then:

CREATE PROCEDURE test(
  v_row IN TABLE_NAME%ROWTYPE
)
IS
  TYPE details_type IS RECORD(
    id   TABLE_NAME.ID1%TYPE,
    name TABLE_NAME.NAME1%TYPE
  );

  TYPE details_tab_type IS TABLE OF details_type;

  details details_tab_type := details_tab_type();
BEGIN
  details.EXTEND(4);

  details(1) := details_type(v_row.id1, v_row.name1);
  details(2) := details_type(v_row.id2, v_row.name2);
  details(3) := details_type(v_row.id3, v_row.name3);
  details(4) := details_type(v_row.id4, v_row.name4);

  FOR i IN 1 .. details.COUNT LOOP
    DBMS_OUTPUT.PUT_LINE(i || ': ' || details(i).id || ', ' || details(i).name);
  END LOOP;
END;
/

All you need to do is write the first assignment statement details(1) := details_type(v_row.id1, v_row.name1); and then copy-paste multiple copies and increment the numbers by 1 each time.

Then you can call it using:

DECLARE
  v_row TABLE_NAME%ROWTYPE;
BEGIN
  SELECT * INTO v_row FROM table_name FETCH FIRST ROW ONLY;
  
  test(v_row);
END;
/

Which outputs:

1: 1, N1
2: 2, N2
3: 3, N3
4: 4, N4

db<>fiddle here

  • Related