Conditional unique constraint with multiple fields in oracle db

后端 未结 3 752
一个人的身影
一个人的身影 2021-01-04 05:12

I have this table:

XPTO_TABLE (id, obj_x, date_x, type_x, status_x)

I wanna create a unique constraint that applies to the fields (ob

相关标签:
3条回答
  • 2021-01-04 05:47

    Under Oracle 11, you can create a bunch of virtual columns that get non-NULL value only when STATUS_X is 5, and then make them unique:

    CREATE TABLE XPTO_TABLE (
      ID INT PRIMARY KEY,
      OBJ_X INT,
      DATE_X DATE,
      TYPE_X VARCHAR2(50),
      STATUS_X INT,
      OBJ_U AS (CASE STATUS_X WHEN 5 THEN OBJ_X ELSE NULL END),
      DATE_U AS (CASE STATUS_X WHEN 5 THEN DATE_X ELSE NULL END),
      TYPE_U AS (CASE STATUS_X WHEN 5 THEN TYPE_X ELSE NULL END),
      UNIQUE (OBJ_U, DATE_U, TYPE_U)
    );
    

    You can freely insert duplicates, as long as STATUS_X is not 5:

    INSERT INTO XPTO_TABLE (ID, OBJ_X, DATE_X, TYPE_X, STATUS_X) VALUES (1, 1, '1-JAN-2014', 'foo', 4);
    INSERT INTO XPTO_TABLE (ID, OBJ_X, DATE_X, TYPE_X, STATUS_X) VALUES (2, 1, '1-JAN-2014', 'foo', 4);
    

    But trying to insert a duplicate when STATUS_X is 5 fails:

    INSERT INTO XPTO_TABLE (ID, OBJ_X, DATE_X, TYPE_X, STATUS_X) VALUES (3, 1, '1-JAN-2014', 'foo', 5);
    INSERT INTO XPTO_TABLE (ID, OBJ_X, DATE_X, TYPE_X, STATUS_X) VALUES (4, 1, '1-JAN-2014', 'foo', 5);
    
    Error report -
    SQL Error: ORA-00001: unique constraint (IFSAPP.SYS_C00139498) violated
    00001. 00000 -  "unique constraint (%s.%s) violated"
    *Cause:    An UPDATE or INSERT statement attempted to insert a duplicate key.
               For Trusted Oracle configured in DBMS MAC mode, you may see
               this message if a duplicate entry exists at a different level.
    *Action:   Either remove the unique restriction or do not insert the key.
    
    0 讨论(0)
  • 2021-01-04 05:54

    Because the CREATE UNIQUE INDEX is expecting only a value you can concatenate the columns as follow

    CREATE UNIQUE INDEX UN_OBJ_DT_TYPE_STATUS
    ON XPTO_TABLE(
    (CASE
         WHEN STATUS_X <> 5
             THEN OBJ_X || TO_CHAR (DATE_X, 'dd/MM/yyyy') || TYPE_X
         ELSE
             NULL
     END));
    
    0 讨论(0)
  • 2021-01-04 06:09

    @jamesfrj: it looks like you are trying to ensure that your table should contain only one record for which status <>5.

    You can try creating a unique functional index by concatenating the columns, as given below

          create table XPTO_TABLE (id number, 
                                obj_x varchar2(20),
                                date_x date,
                                type_x varchar2(20),
                                status_x varchar2(20)                              
                               );
    
          create unique index xpto_table_idx1 on XPTO_TABLE(case when status_x <>'5'  THEN              obj_x||date_x||type_x||STATUS_x ELSE null END);
    

    Hope it helps

    Vishad

    0 讨论(0)
提交回复
热议问题