约束违反异常 PL/SQL

Posted

技术标签:

【中文标题】约束违反异常 PL/SQL【英文标题】:constraint violation exception PL/SQL 【发布时间】:2018-03-04 20:27:02 【问题描述】:

我目前正在处理一项任务,我需要创建一个匿名块来处理违反约束(违规是更新的信用卡数量太少)。我创建了以下不引发错误的块,它只返回约束违规。知道为什么它没有引发我的异常吗?

DECLARE 
my_excep EXCEPTION;
BEGIN
UPDATE mm_member
SET credit_card = '123456789'
WHERE member_id = '14';
IF SQL%ROWCOUNT = 0 THEN
RAISE my_excep;
END IF;
EXCEPTION
WHEN my_excep THEN
DBMS_OUTPUT.PUT_LINE('Failed to update.');
END;

这里创建表

CREATE TABLE mm_member
(member_id  NUMBER(4),
last         VARCHAR(12),
first        VARCHAR(8),
license_no   VARCHAR(9),
license_st   VARCHAR(2),
credit_card  VARCHAR(12),
suspension   VARCHAR(1) DEFAULT 'N',
mailing_list VARCHAR(1),
CONSTRAINT cust_custid_pk PRIMARY KEY (member_id),
CONSTRAINT cust_credcard_ck CHECK (LENGTH(credit_card) = 12));

executed block

【问题讨论】:

【参考方案1】:

您编写的代码完全符合预期 - 如果它没有更新任何内容,则会引发异常,该异常只会执行 DBMS_OUTPUT.PUT_LINE 并显示“更新失败”。

你期望它做什么?

如果您打算真正引发一个异常,您应该这样做(而不是 DBMS_OUTPUT):

raise_application_error(-20000, 'Failed to update');

不过,您所写的任何内容都没有您所描述的,即

违规是更新的信用卡号码太少

这可以使用真正的约束来完成,例如

create table  mm_member
  ( member_id  varchar2(2)
    credit_card varchar2(20) constraint ch_cc check (length(credit_card) = 9),
  );

虽然在我看来,这似乎是一个非常低效的检查。

[编辑:提高示范]

SQL> create table  mm_member
  2    ( member_id  varchar2(2),
  3      credit_card varchar2(20)
  4    );

Table created.

SQL> insert into mm_member (member_id, credit_card) values ('14', '1234');

1 row created.

SQL> -- this will work because there's MEMBER_ID = 14 in the table
SQL> DECLARE
  2    my_excep EXCEPTION;
  3  BEGIN
  4    UPDATE mm_member
  5      SET credit_card = '123456789'
  6      WHERE member_id = '14';
  7
  8    IF SQL%ROWCOUNT = 0 THEN
  9       RAISE my_excep;
 10    END IF;
 11  EXCEPTION
 12    WHEN my_excep THEN
 13      --DBMS_OUTPUT.PUT_LINE('Failed to update.');
 14      raise_application_error(-20000, 'Failed to update');
 15  END;
 16  /

PL/SQL procedure successfully completed.

好的;现在失败了:

SQL> -- changing '14' to something else (for example, '15') will raise an exception
SQL> l6
  6*     WHERE member_id = '14';
SQL> c/14/15
  6*     WHERE member_id = '15';
SQL> /
DECLARE
*
ERROR at line 1:
ORA-20000: Failed to update    --> see? This is an exception
ORA-06512: at line 14


SQL>

[编辑#2:拦截检查约束违规]

由于违反检查约束,这将失败:注意 ORA-02290 错误代码:

SQL> update mm_member set credit_card = '123';
update mm_member set credit_card = '123'
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.CH_CC) violated

您的代码,修改为通过声明 PRAGMA EXCEPTION_INIT 来拦截它使用相同的 2290 错误代码:

SQL> DECLARE
  2    my_excep EXCEPTION;
  3    pragma exception_init (my_excep, -2290);
  4  BEGIN
  5    UPDATE mm_member
  6      SET credit_card = '123456789'
  7      WHERE member_id = '14';
  8
  9    IF SQL%ROWCOUNT = 0 THEN
 10       RAISE my_excep;
 11    END IF;
 12  EXCEPTION
 13    WHEN my_excep THEN
 14      DBMS_OUTPUT.PUT_LINE('I intercepted check constraint - failed to update.');
 15  END;
 16  /
I intercepted check constraint - failed to update.

PL/SQL procedure successfully completed.

SQL>

【讨论】:

它不会引发异常并在我运行它时执行 DBMS 输出。它仍然返回约束冲突。 哪个约束?在任何地方,您的代码中都没有实际的约束。请编辑您的问题并包含CREATE TABLE 声明。同时,我编辑了我的消息并演示了发生了什么。 添加了创建表。如您所见,违反约束是因为新的信用卡号太短(这是故意的,我的任务是创建一个块,但该错误除外) 啊哈。因此,您已经对该列有 CHECK 约束。很好,这就是它应该做的方式。您计划在 PL/SQL 块中使用的异常无效,因为 CHECK 约束首先失败,一旦您尝试将信用卡号更新为长度不同于 12 个字符的值。你的 MY_EXCEP 没有机会提升,Oracle 的内置更快。从我的角度来看,一切都按预期进行。如果您想引发自己的异常,则必须禁用该列上的检查约束。 似乎是 IMO 的冗余分配......所以如果我想绕过 oracles 约束违规返回并拥有自己的 DBMS 输出......我最好的选择是什么?这是确切的分配问题:为此 SQL 命令生成的错误创建一个异常:更新 mm_member set credit_card = 123456789 where member_id = 14;

以上是关于约束违反异常 PL/SQL的主要内容,如果未能解决你的问题,请参考以下文章

PL/SQLPL/SQL过程

约束违反异常 PL/SQL

Oracle——PL/SQL

MediatR 行为的约束违反异常

休眠约束违反异常挂起sql server

指示违反主键约束的异常的名称是啥?