oracle 数据库 - 插入具有唯一键约束的表显示当值实际重复时插入 1 行。 - 发生在函数中

Posted

技术标签:

【中文标题】oracle 数据库 - 插入具有唯一键约束的表显示当值实际重复时插入 1 行。 - 发生在函数中【英文标题】:oracle database - insert into table having unique key constraint shows 1 row(s) inserted when the value is actually duplicate. - happens in a function 【发布时间】:2021-03-28 13:31:11 【问题描述】:

我创建了一个包含 2 列的简单表格 col1 是数字,col2 是电子邮件。 Col1 是一个 pk 并通过一个序列填充,并且我对 col2 有一个唯一的键约束。代码如下所示。

CREATE TABLE  "LISTOFPEOPLETOVIEWPAGE5" 
   (    "PKCOL" NUMBER NOT NULL ENABLE, 
    "EMAIL" VARCHAR2(100), 
     CONSTRAINT "LISTOFPEOPLETOVIEWPAGE5_PK" PRIMARY KEY ("PKCOL")
  USING INDEX  ENABLE, 
     CONSTRAINT "UNIQUE_EMAIL" UNIQUE ("EMAIL")
  USING INDEX  ENABLE
   )
/

CREATE OR REPLACE EDITIONABLE TRIGGER  "BI_LISTOFPEOPLETOVIEWPAGE5" 
  before insert on "LISTOFPEOPLETOVIEWPAGE5"               
  for each row  
begin   
  if :NEW."PKCOL" is null then 
    select "LISTOFPEOPLETOVIEWPAGE5_SEQ1".nextval into :NEW."PKCOL" from sys.dual; 
  end if; 
end; 

/
ALTER TRIGGER  "BI_LISTOFPEOPLETOVIEWPAGE5" ENABLE
/

我在这个表中插入一个电子邮件 ID 说 abc@def.com 并且这成功了。

Insert into LISTOFPEOPLETOVIEWPAGE5 (email) values (abc@def.com);

1 row(s) inserted.

我有一个函数会要求用户提供电子邮件 ID 并将其存储在绑定变量中。此函数检查绑定变量中的值是否已存在于表中。如果是,则输出为“电子邮件已存在”,如果数据库中不存在绑定变量值,则将该值插入表中。

当我运行此函数并向绑定变量提供任何现有电子邮件时,我看到的结果如下: 电子邮件已经存在 已插入 1 行。

代码如下:

declare
v_email varchar2(100);
begin

BEGIN
    select email into v_email from LISTOFPEOPLETOVIEWPAGE5 where email = :EMAIL;
    EXCEPTION
      WHEN NO_DATA_FOUND THEN
        v_email := null;
END;
    if (v_email is null) then
    Insert into LISTOFPEOPLETOVIEWPAGE5 (email) values (:EMAIL);
    else
    dbms_output.put_line('email already exists');
    end if;
end;

output of this function is :
email already exists

1 row(s) inserted.

请帮助我在此功能中哪里出错。为什么我看到插入了 1 行?我期待得到唯一密钥违规错误。

提前致谢。

【问题讨论】:

您可以在email 列上设置唯一约束,以防止重复的电子邮件地址。 我未能在 Windows 10 上使用 Oracle Database 18c Express Edition 重现您描述的行为。 顺便说一句,最好避免使用双引号,除非您真的需要它们。您可能有一些拼写错误,例如空格而不是下划线或混合大小写,并且 CREATE 会成功,并且您稍后只会在某些代码未编译或给出错误结果等时才发现它。 另外,如果您触发了for each row when (new.pkcol is null),则不需要if 检查,也不需要select from dual,因为您可以直接将值指定为@987654328 @ 但是,在我看来,允许在唯一 ID 列中混合生成和手动输入的值是自找麻烦。如果用户输入的值高于当前序列值,则触发器因违反唯一约束而失败只是时间问题。 您从 PL/SQL 代码播种的输出不正确,因为 PL/SQL 不打印插入的行数;所以请显示完整的代码。 【参考方案1】:

我重新创建了您的测试用例,但无法重现您所说的内容。

示例表、序列和触发器:

SQL> CREATE TABLE  "LISTOFPEOPLETOVIEWPAGE5"
  2     (    "PKCOL" NUMBER NOT NULL ENABLE,
  3      "EMAIL" VARCHAR2(100),
  4       CONSTRAINT "LISTOFPEOPLETOVIEWPAGE5_PK" PRIMARY KEY ("PKCOL")
  5    USING INDEX  ENABLE,
  6       CONSTRAINT "UNIQUE_EMAIL" UNIQUE ("EMAIL")
  7    USING INDEX  ENABLE
  8     )
  9  /

Table created.

SQL> create sequence LISTOFPEOPLETOVIEWPAGE5_SEQ1;

Sequence created.

SQL> CREATE OR REPLACE TRIGGER  "BI_LISTOFPEOPLETOVIEWPAGE5"
  2    before insert on "LISTOFPEOPLETOVIEWPAGE5"
  3    for each row
  4  begin
  5    if :NEW."PKCOL" is null then
  6      select "LISTOFPEOPLETOVIEWPAGE5_SEQ1".nextval into :NEW."PKCOL" from sys.dual;
  7    end if;
  8  end;
  9  /

Trigger created.

SQL> Insert into LISTOFPEOPLETOVIEWPAGE5 (email) values ('abc@def.com');

1 row created.

匿名 PL/SQL 块(我使用 SQL*Plus 并将 :EMAIL 更改为 '&&EMAIL',但这不会影响您报告的问题):

SQL> declare
  2    v_email varchar2(100);
  3  begin
  4    BEGIN
  5      select email into v_email from LISTOFPEOPLETOVIEWPAGE5 where email = '&&EMAIL';
  6    EXCEPTION
  7      WHEN NO_DATA_FOUND THEN
  8        v_email := null;
  9    END;
 10
 11    if (v_email is null) then
 12       Insert into LISTOFPEOPLETOVIEWPAGE5 (email) values ('&&EMAIL');
 13    else
 14       dbms_output.put_line('email already exists');
 15    end if;
 16  end;
 17  /
Enter value for email: abc@def.com
email already exists

PL/SQL procedure successfully completed.

SQL> select * From listofpeopletoviewpage5;

     PKCOL EMAIL
---------- ----------------------------------------------------------------------------------------------------
         1 abc@def.com

SQL>

【讨论】:

以上是关于oracle 数据库 - 插入具有唯一键约束的表显示当值实际重复时插入 1 行。 - 发生在函数中的主要内容,如果未能解决你的问题,请参考以下文章

oracle 禁用唯一性约束该如何写语句? 我的表名是OEM_REPOSITORY

1 - SQL Server 2008 之 使用SQL语句创建具有约束条件的表

在其中一列中具有多个空值的复合唯一键约束

oracle - 唯一约束 ORA-00001 与区分大小写的记录

MySQL处理重复键错误插入具有多个唯一索引的表;不是多列唯一索引

[Oracle]约束(constraint)