Oracle 对特定值的唯一约束
Oracle Unique constraint on certain value
我创建了一个 table (test_table),它有两列 (test_IP、test_STATUS)。 table 可以有任意数量的 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))
是否可以对特定值进行唯一约束?如果可以,有人可以帮助我如何实现这一目标吗?提前致谢!
如果 test_status 列可以包含 null 值并且 1 值表示该 ip 处于活动状态,而不是 2 您使用 null 表示不活动,那么唯一约束将起作用。
但我认为这不是一个非常优雅的解决方案。
使用基于唯一函数的索引,它只考虑活动行并将非活动键重置为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 地址一个活动行,则上述解决方案有效。如果您只需要对整个 table 的一个活动行 进行约束,请使用:
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, 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.
我创建了一个 table (test_table),它有两列 (test_IP、test_STATUS)。 table 可以有任意数量的 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))
是否可以对特定值进行唯一约束?如果可以,有人可以帮助我如何实现这一目标吗?提前致谢!
如果 test_status 列可以包含 null 值并且 1 值表示该 ip 处于活动状态,而不是 2 您使用 null 表示不活动,那么唯一约束将起作用。
但我认为这不是一个非常优雅的解决方案。
使用基于唯一函数的索引,它只考虑活动行并将非活动键重置为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 地址一个活动行,则上述解决方案有效。如果您只需要对整个 table 的一个活动行 进行约束,请使用:
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, 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.