如何处理Oracle错误[唯一约束]错误

时间:2015-01-08 06:01:05

标签: sql oracle

我有一个名为TABLE_1的表,它有3列

row_id      row_name    row_descr
1           check1      checks here
2           check2      checks there

这些行是通过前端应用程序创建的。现在假设我从前端删除了带有row_name check2的条目,并使用row_name check3从前端创建了另一个条目,在数据库中我的条目如下。

row_id      row_name    row_descr
1           check1      checks here
3           check3      checks 

现在如果你观察到row_id不是正常的一次性增量,现在我的问题是我正在编写一个insert语句来自动化某些东西,我不知道我应该在row_id列中插入什么。以前我认为它只是新的row_id = old row_id +1。但这不是这种情况。请帮忙

编辑: 目前我正在插入这样的错误:

insert into TABLE1 (row_id, row_name, row_descr
) values ( (select max (row_id) + 1 from TABLE1),'check1','checks here');

row_id不是正常的一次增量。

4 个答案:

答案 0 :(得分:2)

永远不要用max(id)+1来计算id,除非你绝对可以排除同时的动作(这几乎从来就不是这种情况)。在oracle(12版之前,请参阅Kumars回答)创建一个序列,然后插入该序列中的值。

create sequence my_sequence;

通过触发器,这意味着你根本不需要关心插入过程中的ID:

CREATE OR REPLACE TRIGGER myTrigger
BEFORE INSERT ON TABLE1 FOR EACH ROW
BEGIN
  SELECT my_sequence.NEXTVAL INTO :NEW.row_id FROM DUAL;
END;
/

或直接使用插入

insert into TABLE1 (row_id, row_name, row_descr
) values ( my_sequence.nextval,'check1','checks here');

除了在oracle中使用row_id作为列名可能会有点混乱,因为伪列rowid具有特殊含义。

尽管如此:如果您确实需要捕获oracle错误作为删除,可以使用PRAGMA EXCEPTION INIT通过使用插入过程来执行此操作。它可能看起来像这样:

CREATE OR REPLACE PROCEDURE myInsert( [...] )
IS

   value_allready_exists    EXCEPTION;

   PRAGMA EXCEPTION_INIT ( value_allready_exists, -00001 );
   --ORA-00001: unique constraint  violated

BEGIN

 /* 
  *  Do your Insert here
  */ 


  EXCEPTION
    WHEN value_allready_exists THEN 
        /*
         * Do what you think is necessary on your ORA-00001 here
         */
END myInsert;

答案 1 :(得分:1)

Oracle 12c引入了IDENTITY列。确切地说,Release 12.1。在您需要为主键列设置sequence的情况下,它非常方便。

例如,

SQL> DROP TABLE identity_tab PURGE;

Table dropped.

SQL>
SQL> CREATE TABLE identity_tab (
  2    ID          NUMBER GENERATED ALWAYS AS IDENTITY,
  3    text        VARCHAR2(10)
  4  );

Table created.

SQL>
SQL> INSERT INTO identity_tab (text) VALUES ('Text');

1 row created.

SQL> DELETE FROM identity_tab WHERE ID = 1;

1 row deleted.

SQL> INSERT INTO identity_tab (text) VALUES ('Text');

1 row created.

SQL> INSERT INTO identity_tab (text) VALUES ('Text');

1 row created.

SQL> INSERT INTO identity_tab (text) VALUES ('Text');

1 row created.

SQL> DELETE FROM identity_tab WHERE ID = 2;

1 row deleted.

SQL> SELECT * FROM identity_tab;

        ID TEXT
---------- ----------
         3 Text
         4 Text

SQL>

现在让我们看看幕后的内容 -

SQL> SELECT table_name,
  2         column_name,
  3         generation_type,
  4         identity_options
  5  FROM   all_tab_identity_cols
  6  WHERE  owner = 'LALIT'
  7  /

TABLE_NAME           COLUMN_NAME     GENERATION IDENTITY_OPTIONS
-------------------- --------------- ---------- --------------------------------------------------
IDENTITY_TAB         ID              ALWAYS     START WITH: 1, INCREMENT BY: 1, MAX_VALUE: 9999999
                                                999999999999999999999, MIN_VALUE: 1, CYCLE_FLAG: N
                                                , CACHE_SIZE: 20, ORDER_FLAG: N


SQL>

所以,你去吧。由Oracle隐式创建的sequence

不要忘记,您只能使用表sequence的{​​{1}}选项摆脱purge

答案 2 :(得分:0)

如果您不担心导致错误的值,那么可以通过在插入语句中添加/*+ hint */来解决该问题。

在此示例中,我们将从另一个表或一个内部查询中进行选择,然后将结果插入到名为TABLE_NAME的表中,该表对名为IDX_COL_NAME的列具有唯一约束。

INSERT /*+ ignore_row_on_dupkey_index(TABLE_NAME(IDX_COL_NAME)) */ 
INTO TABLE_NAME(
    INDEX_COL_NAME
  , col_1
  , col_2
  , col_3
  , ...
  , col_n)
SELECT 
    INDEX_COL_NAME
  , col_1
  , col_2
  , col_3
  , ...
  , col_n);

Oracle将超越冗余行。如果您担心知道WHICH行导致了此问题或其他原因,那么这不是一个很好的解决方案。但是,如果您对此不关心,只保留插入的第一个值就可以了,那么这应该可以完成工作。

答案 3 :(得分:0)

您可以使用一个异常构建,该异常构建将在唯一键重复的情况下引发


DECLARE
emp_count number;
BEGIN
select count(*) into emp_count from emp;
if emp_count < 1 then
    insert into emp 
    values(1, 'First', 'CLERK', '7839', SYSDATE, 1200, null, 30);
    dbms_output.put_line('Clerk added');
else
    dbms_output.put_line('No data added');
end if; 
EXCEPTION
    when dup_val_on_index then
    dbms_output.put_line('Tried to add row with duplicated index');
END;