【问题标题】:unique constraint violated in stored procedure oracle存储过程oracle中违反了唯一约束
【发布时间】:2023-02-08 17:05:15
【问题描述】:

我有以下存储过程:

create or replace PROCEDURE CALCULATE_RECOVERY_HISTORY(p_month IN VARCHAR2) AS 
l_id NUMBER; 
BEGIN
  ADD_LOG_INFO('CALCULATE_RECOVERY_HISTORY', 'Procedure Started');
  
  l_id := SQ_AP_RECOVERY_HISTORY.NEXTVAL;

    INSERT INTO t_ap_recovery_history (ID, RECOVERY_TARGET_MONTH, TARGET_INSTANCE, RECOVERY_PROGRESS, RECOVERY_TARGET, FAILED_TO_RECOVERY, FOCUS_AREA, IDENTIFIER_CLASS, CREATED_ON) 
    SELECT  l_id,
            a_recovery_target_month, 
            a_target_instance, 
            COUNT(CASE WHEN A_IS_RECOVERED = 'Y' THEN 1 END), 
            COUNT(CASE WHEN A_IS_RECOVERED IN ('Y', 'N') THEN 1 END), 
            COUNT(CASE WHEN A_IS_RECOVERED = 'N' THEN 1 END),
            f.focus_area,
            r.identifier_class,
            SYSDATE
            from t_ap_recovery_target t, t_ap_recovery_focusarea f, range r
    where t.a_focus_area_id = f.id and t.a_range_id = r.id
    and t.a_recovery_target_month = p_month
    group by a_target_instance, a_recovery_target_month, f.focus_area, r.identifier_class;
    
      COMMIT;
END CALCULATE_RECOVERY_HISTORY;

当我运行程序时,出现错误

ORA-00001: 违反唯一约束。

我也试过另一种方法是

SELECT  SQ_AP_RECOVERY_HISTORY.NEXTVAL, a_recovery_target_month ... 

但这也会返回另一个错误,即

此处不允许使用序号

我应该在代码中更改什么来解决这个约束问题?

【问题讨论】:

  • 向我们展示 t_ap_recovery_history 的定义。
  • 今日提示:始终使用现代、明确的JOIN 语法。更易于编写(无错误),更易于阅读和维护,并且在需要时更易于转换为外部连接。

标签: sql oracle stored-procedures plsql


【解决方案1】:

一种选择是让 Oracle 创建 ID。您没有指定您使用的数据库版本,所以肯定会触发什么会起作用:

create or replace trigger trg_bi_rec_hist
  before insert on t_ap_recovery_history
  for each row
begin
  :new.id := SQ_AP_RECOVERY_HISTORY.NEXTVAL;
end;
/

然后过程将不包含插入 ID 列,即

INSERT INTO t_ap_recovery_history (RECOVERY_TARGET_MONTH, ...)
SELECT a_recovery_target_month, ...

另一种选择(如果您的数据库版本支持它)是创建 ID 作为标识列而不是触发器,例如

SQL> create table test
  2    (id number generated always as identity);

Table created.

【讨论】:

    【解决方案2】:

    或者,如果您不想像上一个答案那样创建触发器,则该过程应如下所示:

    创建或替换 PROCEDURE CALCULATE_RECOVERY_HISTORY(p_month IN VARCHAR2) AS l_id 号码; 开始 ADD_LOG_INFO('CALCULATE_RECOVERY_HISTORY', '程序开始');

      INSERT INTO t_ap_recovery_history (ID, RECOVERY_TARGET_MONTH, 
        TARGET_INSTANCE, RECOVERY_PROGRESS, RECOVERY_TARGET,
        FAILED_TO_RECOVERY, FOCUS_AREA, IDENTIFIER_CLASS, CREATED_ON) 
      SELECT  SQ_AP_RECOVERY_HISTORY.NEXTVAL,
           a_recovery_target_month, 
           a_target_instance, 
           COUNT(CASE WHEN A_IS_RECOVERED = 'Y' THEN 1 END), 
           COUNT(CASE WHEN A_IS_RECOVERED IN ('Y', 'N') THEN 1 END), 
           COUNT(CASE WHEN A_IS_RECOVERED = 'N' THEN 1 END),
           f.focus_area,
           r.identifier_class,
           SYSDATE
      from t_ap_recovery_target t, t_ap_recovery_focusarea f, range r
      where t.a_focus_area_id = f.id and t.a_range_id = r.id
          and t.a_recovery_target_month = p_month
      group by a_target_instance, a_recovery_target_month, 
        f.focus_area, r.identifier_class;
    
      COMMIT;
    

    结束 CALCULATE_RECOVERY_HISTORY;

    通常,如果您插入选择一次插入大量行,或者大量更新或大量删除或合并,则触发器会对性能产生不利影响。 如果您只有影响少量行的 DML,触发器可能会降低复杂性,尽管我宁愿在存储过程中做更多的事情而在触发器中做的更少。

    【讨论】:

    • 那行不通的。瓦尼已经试过了。由于 GROUP BY 子句,不能以这种方式使用序列。
    猜你喜欢
    • 1970-01-01
    • 2020-04-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多