【问题标题】:Oracle Unique constraint on certain valueOracle 对某个值的唯一约束
【发布时间】:2021-04-22 12:57:16
【问题描述】:

我创建了一个表 (test_table),它有两列 (test_IP, test_STATUS)。该表可以有任意数量的 IP,但是,只能允许一个状态为“活动”的 IP。可以允许任意数量的“非活动”状态。供参考(活跃 = 1,不活跃 = 2)

例如:

test_IP           test_STATUS
==============================
1.2.3.4            1   
1.2.3.5            2   
1.2.3.6            2   
1.2.3.7            2    
1.2.3.8            1 -- this should now fail (as there are multiple values containing 1 (Active))    

是否可以对特定值具有唯一约束?如果是这样,有人可以帮助我如何实现这一目标吗?提前致谢!

【问题讨论】:

    标签: oracle constraints unique


    【解决方案1】:

    使用基于唯一函数的索引,它只考虑活动行并将非活动键重置为NULL

    例子

    select * from tab order by 1,2;
    
    TEST_IP TEST_STATUS
    ------- -----------
    1.1.1.1           1
    1.1.1.1           2
    1.1.1.1           2
    1.1.1.1           2
    1.1.1.2           1
    
    create unique index tab_ixd on tab (case when  test_STATUS = 1 then test_IP end);
    
    insert into tab (test_IP,test_STATUS) values ('1.1.1.1', 2);
    1 row inserted.
    
    insert into tab (test_IP,test_STATUS) values ('1.1.1.1', 1);
    ORA-00001: unique constraint (ZZZZ.TAB_IXD) violated
    

    如果您允许一个活动行每个 IP 地址,则上述解决方案有效。如果您需要一个整个表中只有一个活动行的约束,请使用:

    create unique index tab_ixd on tab (case when  test_STATUS = 1 then test_STATUS  end);
    

    【讨论】:

      【解决方案2】:

      我会添加虚拟隐形列is_active

      alter table ip_list
         add is_active varchar2(1) 
             invisible 
             generated always as 
                (case when test_STATUS=1 then 'y' end) virtual;
      
      alter table ip_list add constraint uq_active_ip unique (is_active);
      

      由于它是不可见的,因此不会影响现有的查询。只有在查询中指定is_active 才能获取。

      完整示例:

      SQL> create table ip_list(test_IP,test_STATUS)
        2  as
        3  select '1.2.3.4', 1 from dual union all
        4  select '1.2.3.5', 2 from dual union all
        5  select '1.2.3.6', 2 from dual union all
        6  select '1.2.3.7', 2 from dual ;
      
      Table created.
      
      SQL> alter table ip_list add is_active varchar2(1) invisible generated always as (case when test_STATUS=1 then 'y' end) virtual;
      
      Table altered.
      
      SQL> alter table ip_list add constraint uq_active_ip unique (is_active);
      
      Table altered.
      
      SQL> insert into ip_list(test_ip, test_status) values('1.2.3.8',1);
      insert into ip_list(test_ip, test_status) values('1.2.3.8',1)
      *
      ERROR at line 1:
      ORA-00001: unique constraint (XTENDER.UQ_ACTIVE_IP) violated
      
      -- note that * does not return this new column:
      SQL> select * from ip_list;
      
      TEST_IP TEST_STATUS
      ------- -----------
      1.2.3.4           1
      1.2.3.5           2
      1.2.3.6           2
      1.2.3.7           2
      
      -- but you can use it to filter active rows:
      SQL> select * from ip_list where is_active='y';
      
      TEST_IP TEST_STATUS
      ------- -----------
      1.2.3.4           1
      
      1 row selected.
      

      【讨论】:

        【解决方案3】:

        如果 test_status 列可以包含 null 值并且 1 值表示 ip 处于活动状态,而不是 2 您使用 null 表示不活动,则唯一约束将起作用。

        但我认为这不是一个真正优雅的解决方案。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-11-23
          • 2010-12-16
          相关资源
          最近更新 更多