问题描述:

有一次Oracle插入数据冲突,需要删除旧数据再重新插入。

现在根据索引名称(index_name)和用户名(index_owner)即可找到主键包含的列。

但是在想要根据主键删除旧的行数据时发现查不到主键索引所包含的列名。

select column_name from dba_ind_columns where index_name = 'SYS_C0083355' and index_owner = 'CESHI'

就上面这一条语句正常来说应该显示主键所包含的列,如下图

非主键当索引 非主键索引可以为空吗_非主键当索引

但是我的查询结果却是Null,这就导致想要找到主键包含的列不成功。

但是在执行下面这条语句时约束名SYS_C0083355是确实存在的,而且这个约束确实属于这个表。

select * from sys.DBA_CONSTRAINTS where table_name='AC'

非主键当索引 非主键索引可以为空吗_数据库_02

结果中有SYS_C0083355,也就是说这个此索引存在但是没有包含任何列或者约束存在但是约束对应的这个索引不存在。

目前的解决方案是:

删除原有的主键所含列的索引和主键,重新为这个表建立主键,此时就会恢复正常。

语句如下:

ALTER TABLE 用户名.表名 DROP CONSTRAINT SYS_C0083355(约束名);

drop index 索引名;

alter table 用户名.表名 add  primary key(字段1,字段2);

经过测试发现,如果先为某一个字段建立索引,然后再把它设置为主键,就会出现这种情况。但是先设置主键再去给这个字段设置索引则会报错:ORA-01408: 此列列表已索引,说明一个列组合应该只允许有一个索引。

 

分析如下:

唯一索引不允许出现重复值,主键索引不仅不允许重复值而且不允许出现Null。

非主键当索引 非主键索引可以为空吗_oracle_03

图中可以看到把ID列约束成了主键,而主键是唯一的,所以这个约束也应该是唯一的,建立唯一约束的同时会自动建立唯一索引。所以猜测上文的错误是因为手动设置索引在前,设置主键在后,导致因设置主键而默认生成的这个约束发现该字段已经有了索引,于是这个约束就不能再去新建索引。而我代码中的index_name只是刚好和约束名同名而已,约束存在,索引不存在。

错误复现步骤:

1.建表,不要设置主键。

2.为表中某一字段创建索引。

3.把上一步的字段设为主键。

4.执行  

select * from sys.DBA_CONSTRAINTS where table_name='AC(表名)'

可以看到CONSTRAINT_NAME字段,即索引的名字。

5.执行

select * from dba_ind_columns where index_owner = 'CESHI(用户名)'
 AND  index_name='SYS_C0083355(索引名)'

6.看到结果中表名为AC的行中COLUMN_NAME这一列为空

 

如果哪位同学清楚其中原因,请评论在下方或者私信我,一起学习下。