Использование курсора для обновления вложенных таблиц pl / sql - PullRequest
0 голосов
/ 11 ноября 2018

у меня есть вложенная таблица

create or replace type comm_type as object
 (comm_month varchar(5),
 comm_amount  number); 

create or replace TYPE comm_array AS VARRAY(12) OF comm_type;

alter table emp2 add commission comm_array

Теперь вопрос в том, как я могу обновить comm_amount столбец, используя курсор ?

Пока у меня есть это, но я не могу получить доступ к дополнительной таблице (комиссия, какие-либо предложения?

DECLARE 
  CURSOR c_comm_amount_cursor IS 
   select c.comm_amount
    from emp2 e, table (e.commission) c
    where c.comm_month = 'DEC' for update of c.comm_month nowait;
BEGIN
   FOR emp_record IN c_comm_amount_cursor LOOP
    UPDATE emp2
     SET  emp2.commission.comm_amount = emp2.commission.comm_amount + 100
     WHERE CURRENT OF c_emp_cursor;
  END LOOP;
END;
/

EDIT

Вот описание моей таблицы:

Name       Null?    Type         
---------- -------- ------------ 
EMPNO      NOT NULL NUMBER(4)    
ENAME               VARCHAR2(10)    
BONUS               NUMBER       
COMMISSION          COMM_ARRAY

comm_array->12*times(comm_month, comm_amount)

И я хочу обновить comm_amount за определенный месяц.

РЕШЕНИЕ

DECLARE 
  CURSOR c_comm_amount_cursor IS 
   select c.comm_amount,c.comm_month, e.empno
    from emp2 e, table (e.commission) c
    where c.comm_month = 'DEC'for update of c.comm_month nowait;

BEGIN
  FOR emp_record IN c_comm_amount_cursor 
  LOOP
     UPDATE table(Select commission from emp2 where empno = emp_record.empno) e 
     SET  e.comm_amount = e.comm_amount + 100
     WHERE CURRENT OF c_comm_amount_cursor;
 END LOOP;
END;
/

Ответы [ 2 ]

0 голосов
/ 11 ноября 2018

Есть несколько ограничений при использовании varrays. Один из них - когда вы делаете DML операции с таблицами, имеющими столбцы с типом данных varray, как показано в вашем примере. Вы можете использовать Nested table и выполнить свое требование, как показано ниже в моей демонстрации. Однако имейте в виду, что операции с вложенными таблицами довольно сложны для понимания. Смотрите ниже и читайте встроенные комментарии.

--Created Table emp2 with an additional column
CREATE TABLE emp2 (ename VARCHAR2(10));

--Object 
CREATE OR REPLACE TYPE COMM_TYPE AS OBJECT
 (COMM_MONTH VARCHAR(5),
 COMM_AMOUNT  NUMBER); 

--Created a Table of object rather then varray.
CREATE OR REPLACE  TYPE COMM_ARRAY AS TABLE OF COMM_TYPE;

--Modified table emp2. Added column commission as shown in your example
ALTER  TABLE EMP2 ADD COMMISSION COMM_ARRAY NESTED TABLE COMMISSION STORE AS TBA1;

--Inserted records
INSERT INTO EMP2 VALUES('AAA',COMM_ARRAY(COMM_TYPE('NOV',100)));
INSERT INTO EMP2 VALUES('BBB',COMM_ARRAY(COMM_TYPE('DEC',200)));

--Selected Records
SQL> SELECT C.COMM_AMOUNT,C.COMM_MONTH
  2      FROM EMP2 E, TABLE (E.COMMISSION) C
  3      WHERE C.COMM_MONTH = 'DEC';

COMM_AMOUNT COMM_
----------- -----
        200 DEC   

- Блокировать обновление записей

DECLARE 
  CURSOR c_comm_amount_cursor IS 
   select c.comm_amount,c.comm_month
    from emp2 e, table (e.commission) c
    where c.comm_month = 'DEC'for update of c.comm_month nowait;
BEGIN
  FOR emp_record IN c_comm_amount_cursor 
  LOOP
     --With the help of table operator you can update records of a nested table but not varray.
     UPDATE table( Select commission from emp2 where ename = 'BBB') e --<--Make sure to use additional column of the table to make unique record selection for update
     SET  e.comm_amount = e.comm_amount + 100    
     WHERE CURRENT OF c_comm_amount_cursor;
 END LOOP;
 COMMIT;
END;
/

- Вы видите, что обновление выполняется.

SQL> /

COMM_AMOUNT COMM_
----------- -----
        300 DEC

Кроме того, как упоминалось в комментариях, использование цикла выглядит избыточным, и блок может быть дополнительно упрощен, как показано ниже:

BEGIN
     --With the help of table operator you can update records of a nested table but not varray.
 UPDATE table( Select commission from emp2 where ename = 'BBB') e --<--Make sure to use additional column of the table to make unique record selection for update
   SET  e.comm_amount = e.comm_amount + 100    
   WHERE  e.comm_month ='DEC';

 COMMIT;
END;

EDIT:

как я могу обновить каждого сотрудника, здесь вы выбираете только одного с именем 'BBB'. Есть ли способ?

Как уже упоминалось в моих комментариях, вы можете использовать dynamic SQL для обновления всех сотрудников, как показано ниже:

DECLARE 
v_sql varchar2(2000);
CURSOR c_enme_cursor IS 
   select ename
    from emp2;
BEGIN
FOR emp_recd IN c_enme_cursor 
LOOP
 v_sql:=q'[
           UPDATE table( Select commission from emp2 where ename = ']'||emp_recd.ename||q'[') e 
             SET  e.comm_amount = e.comm_amount + 100    
            -- WHERE  e.comm_month ='DEC'
          ]';
  EXECUTE IMMEDIATE V_SQL;          
END LOOP;
COMMIT;
END;
0 голосов
/ 11 ноября 2018

Привет быстрый ответ:

DECLARE
   CURSOR C_COMM_AMOUNT_CURSOR
   IS
      SELECT ROWID ROW_ID
      FROM EMP2 E
      WHERE E.COMM_MONTH = 'DEC';
BEGIN
   FOR EMP_RECORD IN C_COMM_AMOUNT_CURSOR
   LOOP
      UPDATE TABLE (
                    SELECT COMMISSION
                    FROM EMP2
                    WHERE ROWID = ROW_ID
                   )
      SET COMM_AMOUNT = COMM_AMOUNT + 100
      WHERE ;--your where clause condition
   END LOOP;
END;

вы должны знать, что при работе с вложенными таблицами вы должны использовать TABLE () вокруг вложенной таблицы в сценариях SQL, в PL / SQL это немного сложнее, и вам нужно создать запуск вложенного объекта время и заполнить его вашими данными и манипулировать ими, а затем сохранить его на вашей таблице, что слишком далеко, я столкнулся с этой проблемой, и использование ROWID было более читабельным.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...