Oracle 如何将PL/SQL本地定义的类型与表运算符一起使用

Oracle 如何将PL/SQL本地定义的类型与表运算符一起使用,oracle,plsql,Oracle,Plsql,我正在开发一个触发器,用于更新记录部门及其工资总额的表格。每次更新EMP表时。触发器将更新此表。为了避免突变表的错误,我实现了一个复合触发器类型触发器 我把你的实现放在这里: CREATE OR REPLACE TRIGGER EJERCICIO_27 FOR INSERT OR UPDATE OR DELETE ON EMP COMPOUND TRIGGER TYPE t_DeptToUpdate IS TABLE OF NUMBER(2,0); deptToUpdate

我正在开发一个触发器,用于更新记录部门及其工资总额的表格。每次更新EMP表时。触发器将更新此表。为了避免突变表的错误,我实现了一个复合触发器类型触发器

我把你的实现放在这里:

CREATE OR REPLACE TRIGGER EJERCICIO_27 
FOR INSERT OR UPDATE OR DELETE ON EMP
COMPOUND TRIGGER

    TYPE t_DeptToUpdate IS TABLE OF NUMBER(2,0);
    deptToUpdate t_DeptToUpdate;

-- AFTER EACH ROW Section:
AFTER EACH ROW IS
BEGIN

    IF NOT :OLD.DEPTNO MEMBER OF deptToUpdate THEN
        deptToUpdate.EXTEND;
        deptToUpdate(deptToUpdate.LAST) := :OLD.DEPTNO;
    END IF;

END AFTER EACH ROW;
-- AFTER STATEMENT Section:
AFTER STATEMENT IS
BEGIN
    DBMS_OUTPUT.PUT_LINE('SE ACTUALIZAN UN TOTAL DE: ' || deptToUpdate.COUNT);
    MERGE INTO SALARIO_DEPARTAMENTOS SD USING (
        SELECT DEPTNO, NVL(SUM(SAL), 0) AS SUM_TOTAL FROM EMP
        WHERE DEPTNO IN (SELECT * FROM TABLE(deptToUpdate))
        GROUP BY DEPTNO
    ) D
    ON (SD.DEPTNO = D.DEPTNO)
    WHEN MATCHED THEN 
        UPDATE SET
            SAL_TOT = D.SUM_TOTAL
            WHERE SD.DEPTNO = D.DEPTNO
    WHEN NOT MATCHED THEN 
        INSERT (DEPTNO, SAL_TOT)
        VALUES(D.DEPTNO, D.SUM_TOTAL);
EXCEPTION
    WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE('ERROR : ' || SQLCODE || 'MENSAJE: ' || SQLERRM);

END AFTER STATEMENT;
END;
/
我在使用集合作为查询MERGE语句的源时遇到的问题。我知道在Oracle 12c中,我使用的是Oracle 12c R2 Enterprise,我可以使用本地定义类型的表运算符。正如本文所讨论的

编译器返回给我的错误如下:

LINE/COL ERROR
-------- -----------------------------------------------------------------
20/5     PL/SQL: SQL Statement ignored
22/40    PL/SQL: ORA-22905: no se puede acceder a las filas de un elemento de tabla no anidada
22/46    PLS-00642: tipos de recopilación local no permitidos en sentencias SQL
有人可以告诉我使用什么方法,而不必在原理图中创建任何类型?。提前谢谢

编辑 错误信息的翻译:

ORA-22905: Rows of a non-nested table element can not be accessed
PLS-00642: Local collection types not allowed in SQL statements

正如劳德克所评论的那样,维护部门列表和总薪酬的一种非常简单的方法是:

Create Or Replace View salario_departamentos_view As
Select deptno, Sum(sal) As sal_tot From emp
Group By deptno;
此解决方案的妙处在于,数据始终与EMP表完美协调,而且即使对于SQL技能最低的人来说,也很容易理解。

是否需要使用集合?如果不是,那么一个简单的行级触发器应该可以工作,如下所示:

Create Or Replace Trigger emp_trig
After Insert Or Update Or Delete On emp
For Each Row
Begin
  -- Subtract old salary from old department
  Update department_salary ds
     Set ds.tot_salary = ds.tot_salary - :old.salary
   Where ds.dept =  :old.dept;

  If Inserting Or Updating Then
    -- Add new salary to new department
    Update department_salary ds
       Set ds.tot_salary = ds.tot_salary + :new.salary
     Where ds.dept =  :new.dept;

    If SQL%Rowcount = 0 Then
      Insert Into department_salary  (dept, tot_salary) Values(:new.dept, :new.salary);
    End If;
  End If;
End;
/

新旧值的单独update语句处理更新行可能包含更改的部门编号的情况。

尝试将类型定义更改为类型t_DeptToUpdate IS TABLE of number或类型t_DeptToUpdate IS TABLE of EMP.DEPTNO%类型。祝你好运。我有点好奇,为什么你要经历一个触发器更新一个表的麻烦,而你可以创建一个非常简单和快速的视图来为你做这件事,并且总是最新的。也许我遗漏了一些东西,你也可以试试DeTutoupDeD的DePtNo成员,而不是DeTtNo。也许您必须将MERGE转换为INSERT和UPDATE语句。我的理解是,即使在12c中,类型也必须在包规范中定义。如果在包体或触发器中声明类型,则无法工作。感谢您的回复。在建议的练习中,我必须使用触发器。我知道理想的做法是使用视图。谢谢,这太完美了