【问题标题】:Oracle package errorOracle 包错误
【发布时间】:2017-04-27 16:10:19
【问题描述】:

我有一个包,它会从一些表中删除数据。我创建了具有在另一个表和具有初始化逻辑的过程中审计的功能的包。我停止了奇怪的 Ora 错误。也许您知道这里可能出了什么问题。

这是规范:

CREATE OR REPLACE PACKAGE CLIENT_DELETE_PACKAGE
IS
  deletion_results VARCHAR2(200);
  deletedEntries     NUMBER;
  min_date           DATE;
  max_date           DATE;
  -- Enable/disable logging
  Enable_Audit_Trail BOOLEAN := True;
  -- Enable Safe Mode
  Enable_Safe_Mode BOOLEAN := True;
  PROCEDURE AUDIT_TRAIL(
      MyTYPE       IN VARCHAR2,
      MyDATA       IN VARCHAR2,
      MyDatasource IN VARCHAR2,
      MyResultData IN VARCHAR2);
  -- ECHO Check that the package is available.
  FUNCTION ECHO(
      MyDATA IN VARCHAR2)
    RETURN VARCHAR2;
  -- JOB_REQUEST
  FUNCTION DEL_WLM_ALERT(
      MyAlertKey IN NUMBER)
    RETURN VARCHAR2;
  PROCEDURE INIT;
END CLIENT_DELETE_PACKAGE;
/

还有身体:

CREATE OR REPLACE PACKAGE BODY CLIENT_DELETE_PACKAGE
AS
  -- Auditing
  PROCEDURE AUDIT_TRAIL(
      MyTYPE       IN VARCHAR2,
      MyDatasource IN VARCHAR2,
      MyResultData IN VARCHAR2)
  AS
    --allow to keep the entry even if a roll-back occurs in the other procedure.
    pragma autonomous_transaction;
  BEGIN
    /*ID: provided by sequence
    EVENT_TIME: default value SysDate
    TYPE: DELETED/LOCKED ITEM
    DATASOURCE_NAME: datasource name
    RESULT_DATA: data link to type
    */
    IF (Enable_Audit_Trail) THEN
      INSERT INTO CLIENT_DELETION_AUDIT
        ( id, TYPE, DATASOURCE_NAME, RESULT_DATA
        )
      SELECT SEQ_AUDIT_TRAIL.NEXTVAL, MyTYPE, MyDatasource, MyResultData FROM dual;
      COMMIT;
    END IF;
  END AUDIT_TRAIL;
-- -------------------------------------------------------------------------
-- Echoing function
-- -------------------------------------------------------------------------
  FUNCTION ECHO(
      MyDatasource IN VARCHAR2)
    RETURN VARCHAR2
  AS
  BEGIN
    /*check if the package is available */
    RETURN 'i am here';
  END ECHO;
-- -------------------------------------------------------------------------
-- Delete WLM Alert Data
-- -------------------------------------------------------------------------
  FUNCTION DEL_WLM_ALERT(
      MyAlertKey IN NUMBER)
    RETURN VARCHAR2
  AS
    countLookUp       NUMBER;
    countTotalEntries NUMBER;
    deletedEntries    NUMBER;
    dataSourceToCheck VARCHAR2(200);
    numberOfAlertLeft NUMBER;
    alert_trx_id      NUMBER;
    trx_group_id      NUMBER;
    large_str_id      NUMBER;
  BEGIN
    countTotalEntries:=0;
    deletedEntries   :=0;
    ---Get transaction ID for usage later---
    SELECT TRANSACTION_ID
    INTO alert_trx_id
    FROM WLM_RULE_ALERT WRA
    JOIN WLM_ALERT_HEADER WAH
    ON WAH.ALERT_IDENTIFIER = WRA.ALERT_IDENTIFIER
    WHERE wah.alert_key     = MyAlertKey
    AND rownum              =1;
    ---Get transaction GRoup ID for usage later---
    SELECT TRANSACTION_GROUP_ID
    INTO trx_group_id
    FROM ALERTING_TRANSACTION AT
    JOIN WLM_RULE_ALERT WRA
    ON WRA.TRANSACTION_ID = AT.ID
    JOIN WLM_ALERT_HEADER WAH
    ON WAH.ALERT_IDENTIFIER = WRA.ALERT_IDENTIFIER
    WHERE wah.alert_key     = MyAlertKey
    AND rownum              =1;
    ---Get LargeString ID for usage later---
    SELECT MIN(tg.largestring_id)
    INTO large_str_id
    FROM transaction_group tg
    WHERE tg.ID = trx_group_id
    AND rownum  =1;
    -- deleted from ALERT_MATCH_DATA --
    DELETE
    FROM ALERT_MATCH_DATA AMD
    WHERE ALERT_MATCH_ID IN
      (SELECT AM.ID
      FROM ALERT_MATCH AM
      JOIN WLM_RULE_ALERT WRA
      ON WRA.id = AM.WLM_RULE_ALERT_ID
      JOIN WLM_ALERT_HEADER WAH
      ON WAH.ALERT_IDENTIFIER = WRA.ALERT_IDENTIFIER
      WHERE wah.alert_key     = MyAlertKey
      );
    -- deleted from ALERT_MATCH --
    DELETE
    FROM ALERT_MATCH AM
    WHERE AM.WLM_RULE_ALERT_ID IN
      (SELECT WRA.id
      FROM WLM_RULE_ALERT WRA
      JOIN WLM_ALERT_HEADER WAH
      ON WAH.ALERT_IDENTIFIER = WRA.ALERT_IDENTIFIER
      WHERE wah.alert_key     = MyAlertKey
      );
    deletedEntries      :=deletedEntries+SQL%ROWCOUNT;
    IF(numberOfAlertLeft =0) THEN
      -- deleted from DATA_SOURCE_CUSTOMER --
      DELETE
      FROM DATA_SOURCE_CUSTOMER DSC
      WHERE ID       = alert_trx_id;
      deletedEntries:=deletedEntries+SQL%ROWCOUNT;
      -- deleted from DATA_SOURCE_SWIFT --
      DELETE
      FROM DATA_SOURCE_SWIFT DSC
      WHERE ID       = alert_trx_id;
      deletedEntries:=deletedEntries+SQL%ROWCOUNT;
      -- deleted from ALERTING_TRANSACTION --
      DELETE
      FROM ALERTING_TRANSACTION AT
      WHERE AT.ID                = alert_trx_id
      OR AT.TRANSACTION_GROUP_ID = trx_group_id;
      deletedEntries            :=deletedEntries+SQL%ROWCOUNT;
      IF( countLookUp            = 1 ) THEN
        -- deleted from TRANSACTION_GROUP --
        DELETE
        FROM TRANSACTION_GROUP AT
        WHERE AT.ID    = trx_group_id;
        deletedEntries:=deletedEntries+SQL%ROWCOUNT;
        -- deleted from LARGESTRING_PART --
        DELETE
        FROM LARGESTRING_PART
        WHERE LARGESTRING_ID                IN large_str_id;
        deletedEntries       :=deletedEntries+SQL%ROWCOUNT;
        -- deleted from LARGESTRING --
        DELETE
        FROM LARGESTRING
        WHERE id       = large_str_id;
        deletedEntries:=deletedEntries+SQL%ROWCOUNT;
      END IF;
    END IF;
    countTotalEntries:=countTotalEntries+countLookUp;
    -- deleted from WLM_RULE_ALERT --
    DELETE
    FROM WLM_RULE_ALERT WRA
    WHERE WRA.ALERT_IDENTIFIER IN
      (SELECT WAH.ALERT_IDENTIFIER
      FROM WLM_ALERT_HEADER WAH
      WHERE wah.alert_key= MyAlertKey
      );
    deletedEntries:=deletedEntries+SQL%ROWCOUNT;
    -- deleted from WLM_CUSTOMER_MATCH_DETAILS --
    DELETE
    FROM WLM_CUSTOMER_MATCH_DETAILS
    WHERE ALERT_KEY= MyAlertKey;
    deletedEntries:=deletedEntries+SQL%ROWCOUNT;
    -- deleted from WORKFLOW_ACTION_LOG --
    DELETE
    FROM WORKFLOW_ACTION_LOG
    WHERE WORKFLOW_WORKITEM_ID IN
      (SELECT id
      FROM WORKFLOW_WORKITEM
      WHERE ENTITY_KEY=TO_CHAR(MyAlertKey)
      AND ENTITY_NAME ='WLM Alert'
      );
    deletedEntries:=deletedEntries+SQL%ROWCOUNT;
    -- deleted from WORKFLOW_WORKITEM_LINK --
    DELETE
    FROM WORKFLOW_WORKITEM_LINK
    WHERE ENTITY_KEY=MyAlertKey
    AND ENTITY_NAME ='WLM Alert';
    deletedEntries :=deletedEntries+SQL%ROWCOUNT;
    -- deleted from WORKFLOW_WORKITEM --
    DELETE
    FROM WORKFLOW_WORKITEM
    WHERE ENTITY_KEY= TO_CHAR(MyAlertKey)
    AND entity_name ='WLM Alert';
    deletedEntries :=deletedEntries+SQL%ROWCOUNT;
    -- deleted from WLM_ALERT_HEADER --
    DELETE
    FROM WLM_ALERT_HEADER
    WHERE alert_key = MyAlertKey;
    deletedEntries :=deletedEntries+SQL%ROWCOUNT;
  END DEL_WLM_ALERT;
-- initialization procedure
  PROCEDURE INIT
  AS
    CURSOR alert_id
    IS
    WITH alerts AS
      (SELECT wah.ALERT_KEY                                                     AS alert_key,
        ds.NAME                                                                 AS datasource_name,
        NVL(el.ENTITY_ID,0)                                                     AS alert_key_locked,
        MIN(EVENT_DATE) OVER (PARTITION BY DATASOURCE_NAME order by EVENT_DATE) AS min_date,
        MAX(EVENT_DATE) OVER (PARTITION BY DATASOURCE_NAME order by EVENT_DATE) AS max_date
      FROM WLM_ALERT_HEADER wah
      LEFT JOIN WORKFLOW_WORKITEM ww
      ON wah.ALERT_KEY=ww.ENTITY_KEY
      LEFT JOIN DATA_SOURCE ds
      ON wah.AT_DATASOURCE_ID=ds.ID
      LEFT JOIN CLIENT_DELETION_SETTINGS rds
      ON ds.NAME =rds.DATASOURCE_NAME
      LEFT JOIN ENTITY_LOCKS el
      ON el.ENTITY_ID  =wah.ALERT_KEY
      WHERE EVENT_DATE < (sysdate - rds.PERIOD)
    UNION ALL
    SELECT wah.ALERT_KEY                                                      AS alert_key,
      ds.NAME                                                                 AS datasource_name,
      NVL(el.ENTITY_ID,0)                                                     AS alert_key_locked,
      MIN(EVENT_DATE) OVER (PARTITION BY DATASOURCE_NAME order by EVENT_DATE) AS min_date,
      MAX(EVENT_DATE) OVER (PARTITION BY DATASOURCE_NAME order by EVENT_DATE) AS max_date
    FROM WLM_ALERT_HEADER wah
    LEFT JOIN WORKFLOW_WORKITEM ww
    ON wah.ALERT_KEY=ww.ENTITY_KEY
    LEFT JOIN
      (SELECT ID, NAME
      FROM DATA_SOURCE
      WHERE NAME NOT IN
        (SELECT DATASOURCE_NAME FROM CLIENT_DELETION_SETTINGS
        )
      ) ds
    ON wah.AT_DATASOURCE_ID=ds.ID
    LEFT JOIN CLIENT_DELETION_SETTINGS rds
    ON ds.NAME =rds.DATASOURCE_NAME
    LEFT JOIN ENTITY_LOCKS el
    ON el.ENTITY_ID  = wah.ALERT_KEY
    WHERE EVENT_DATE < (sysdate -
      (SELECT period FROM CLIENT_deletion_settings WHERE datasource_name='DEFAULT'
      ))
      )
    SELECT *
    FROM CLIENT_DELETION_SETTINGS rbs
    LEFT JOIN alerts al
    ON al.datasource_name=rbs.datasource_name;

  BEGIN
    FOR x IN alert_id
    LOOP
      IF (x.alert_key_locked > 0) THEN
        AUDIT_TRAIL('LOCKED', x.datasource_name, x.alert_key);
        COMMIT;
      ELSE
        -- execute deletion for each alert_id
        deletion_results:=DEL_WLM_ALERT(x.alert_key);
        COMMIT;
      END IF;
      AUDIT_TRAIL('DELETED', x.datasource_name, deletedEntries || ' | ' || MIN(min_date) || ' -- ' || MAX(max_date));
    END LOOP;
END INIT;
END CLIENT_DELETE_PACKAGE;
/

这些是错误:

Error(11,13): PLS-00323: subprogram or cursor 'AUDIT_TRAIL' is declared in a package specification and must be defined in the package body
Error(17,12): PLS-00323: subprogram or cursor 'ECHO' is declared in a package specification and must be defined in the package body
Error(234,9): PL/SQL: Statement ignored
Error(234,33): PLS-00302: component 'DATASOURCE_NAME' must be declared
Error(241,7): PL/SQL: Statement ignoredError(241,32): PLS-00302: component 'DATASOURCE_NAME' must be declared
Error(241,32): PLS-00302: component 'DATASOURCE_NAME' must be declared

【问题讨论】:

  • 我只想补充一点:子程序或游标'AUDIT_TRAIL'在包规范中声明,必须在包主体中定义错误(17,12):它已声明,也是下一个函数……这让我抓狂。在此先感谢并祝您有美好的一天:)

标签: oracle plsql package


【解决方案1】:

您已经在两个地方声明了过程和函数,但是参数不同,因此 PL/SQL 编译器将它们视为不同的东西。您有一个在规范中声明但从未定义的过程和函数;以及身体私有的过程和功能 - 它们是完全独立的。

您需要更改规格以匹配:

CREATE OR REPLACE PACKAGE CLIENT_DELETE_PACKAGE
IS
  ...
  PROCEDURE AUDIT_TRAIL(
      MyTYPE       IN VARCHAR2,
      -- MyDATA       IN VARCHAR2, -- this isn't in the body version
      MyDatasource IN VARCHAR2,
      MyResultData IN VARCHAR2);
  -- ECHO Check that the package is available.
  FUNCTION ECHO(
      -- MyDATA IN VARCHAR2) -- wrong name
      MyDatasource IN VARCHAR2)
    RETURN VARCHAR2;
  ...

PLS-00302 是因为您的游标查询中有重复的列名。您可以通过一个简化的示例看到什么。如果您运行如下查询:

column dummy format a6

select *
from dual
cross join dual;

DUMMY  DUMMY 
------ ------
X      X     

客户端可以在结果集中显示具有相同标题的两列。例如,如果您尝试基于该查询创建视图,则会收到“ORA-00957:重复列名”错误,因为视图 ​​DDL 中的列名必须相同。

这里发生了类似的事情,但是游标被隐式地赋予了两列的唯一列别名。正如连接条件ON al.datasource_name=rbs.datasource_name 所示,相同的列名出现在您要连接在一起的表和CTE 中,因此select * 将获得相同的列名两次。由于两者都隐含地被别名为独特的东西,因此在游标记录类型中没有实际称为 datasource_name 的列。

您应该将光标查询更改为不使用毯子select *;从表和 CTE 中列出您实际需要的列。无论如何,这通常是可取的。

【讨论】:

  • 很好的答案/解释。另外,关于不使用'select *'的优点
【解决方案2】:

您的 AUDIT_TRAIL 规范未遵循其主体声明。两个“标题”必须相同 - 相同的参数。包括 arg 名称。

ECHO 也是如此。

关于 DATASOURCE_NAME - 它真的是表 CLIENT_DELETION_AUDIT 中的一列吗?是不是不见了?

【讨论】:

  • 非常感谢您的快速回答。我只留下了两个错误:错误(235,33):PLS-00302:必须声明组件'DATASOURCE_NAME'错误(242,32):PLS-00302:必须声明组件'DATASOURCE_NAME' 这是desc CLIENT_DELETION_AUDIT的结果:名称空类型 --------------- -------- ------------- ID NOT NULL NUMBER EVENT_TIME DATE TYPE VARCHAR2(200) DATASOURCE_NAME VARCHAR2(200) RESULT_DATA VARCHAR2(200)
  • 我会说问题出在TYPE 列名中。 TYPE 是Oracle 的保留字。所以它会导致 SQL 语句出现问题。您可以尝试使用引号:insert into... (..., "TYPE", ...),或将列名更改为 eg。 ITEM_TYPE
  • @pvanek - TYPE 是 keyword,但不是 reserved word。它可能会导致问题,但这不是问题所在。异常在游标循环中被抛出。
猜你喜欢
  • 2011-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-20
  • 2020-09-10
  • 1970-01-01
相关资源
最近更新 更多