如何解决Oracle 对特定值的唯一约束
我创建了一个表(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))
是否可以对特定值进行唯一约束?如果是这样,有人可以帮助我如何实现这一目标吗?提前致谢!
解决方法
使用基于唯一函数的索引,只考虑活动行并将非活动键重置为 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,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);
,
我会添加虚拟隐形列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,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.
,
如果 test_status 列可以包含 null 值并且 1 值表示 ip 处于活动状态,并且您使用 null 而不是 2 表示不活动,那么唯一约束将起作用。
但我认为这不是一个真正优雅的解决方案。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。