我在SO上看到了这个例子,它给出了一个通过忽略空值来创建唯一索引的解决方案。但是,我想扩展它,我无法达成解决方案。
我有一个表的3列的复合索引(表中还有其他10列)。这些列不是PK的一部分。在这3列中,2将始终保留一些值,第3列可能为NULL。我有大量的测试数据,并且有许多插入,其中2列具有相同的值,第3列为NULL。这些所有插件都适用于PostgreSQL,但Oracle抱怨道。为了让我的测试用例工作,我认为我认为最简单的解决方案是尝试一个独特的Oracle索引,它可以在PostgreSQL中运行。
准确地说:我想要一种以下类型的结构,不确定如何组合col1 + col2 + col3
create unique index tbl_idx on tbl (nvl2(col3, col1 + col2, col1 + col2 + col3))
我正在使用liquibase。索引按以下方式创建 -
<changeSet dbms="postgresql,oracle" author="abc" id="222">
<createIndex indexName="Index_7" schemaName="ss" tableName="Users" unique="true">
<column name="idOrganization"/>
<column name="strUsername"/>
<column name="strNotDeleted"/>
</createIndex>
</changeSet>
我正在使用liquibase来创建我的测试数据,这里有两个插入语句
<insert schemaName="ss" tableName="Users">
<column name="strUsername" value="user1" />
<column name="idUser" valueNumeric="20741" />
<column name="idOrganization" valueNumeric="4" />
<column name="strFirstName" value="user" />
<column name="strLastName" value="one" />
<column name="strEmail" value="email@foo.com" />
<column name="strNotDeleted" />
</insert>
<insert schemaName="ss" tableName="Users">
<column name="strUsername" value="user1" />
<column name="idUser" valueNumeric="20771" />
<column name="idOrganization" valueNumeric="4" />
<column name="strFirstName" value="user" />
<column name="strLastName" value="one" />
<column name="strEmail" value="email@foo.com" />
<column name="strNotDeleted" />
</insert>
这两个插件适用于PostgreSQL,但是对于Oracle出现错误而导致错误&#34; Index_7约束违规&#34;。
答案 0 :(得分:10)
如果目标只是为了防止将strNotDeleted
设置为非NULL值的重复,那么你需要一个像这样的基于函数的索引
SQL> create table users(
2 idOrganization number,
3 strUsername varchar2(100),
4 strNotDeleted varchar2(3)
5 );
Table created.
SQL> create unique index idx_users
2 on users( (case when strNotDeleted is not null
3 then idOrganization
4 else null
5 end),
6 (case when strNotDeleted is not null
7 then strUsername
8 else null
9 end) );
Index created.
这允许插入您在问题中提到的两行
SQL> insert into users values( 4, 'user', null );
1 row created.
SQL> insert into users values( 4, 'user', null );
1 row created.
您可以在strNotNull
列设置为非NULL值
SQL> insert into users values( 4, 'user', 'Yes' );
1 row created.
但是你无法插入第二行
SQL> insert into users values( 4, 'user', 'Yes' );
insert into users values( 4, 'user', 'Yes' )
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.IDX_USERS) violated
在幕后,Oracle b * -tree索引不会完全索引NULL
条目。如果CASE
不是idOrganization
,则两个strUsername
语句可确保索引仅包含strNotDeleted
和NULL
的条目。如果strNotDeleted
为NULL
,则两个CASE
语句都会计算为NULL
,并且索引中不会生成任何条目。从概念上讲,它类似于其他数据库中的部分索引,它允许您在索引上指定WHERE
子句,以便只索引“有趣”的行。
答案 1 :(得分:0)
SQL> create table users(
idOrganization number,
strUsername varchar2(100),
strNotDeleted varchar2(3)
)
SQL> /
Table created.
SQL> Create unique index idx_users
on users(
(
case when strNotDeleted is not null
then idOrganization
else null
end
),
(
case when strNotDeleted is not null
then strUsername
else null
end
),
(
case when strNotDeleted is not null
then strNotDeleted
else null
end
)
)
SQL> /
Index created.