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 与区分大小写的记录