作为一个Oracle数据库开发者或者DBA,经常需要对一些表的一列或几列来创建索引,为行提供直接的快速存取。但在创建时,经常会遇到这样的提示:

ORA-01452:不能创建惟一索引,发现重复记录。

Oracle系统提示不能对表创建一个惟一索引,是因为系统发现表中存在重复的记录。只有先找到表中的重复记录并删除该记录,才可以创建惟一索引。下面以表table_name为例,介绍三种不同的方法来确定库表中重复的记录。
<h3>1.利用分组函数查找表中的重复行</h3>

利用 select 语句中的分组函数 GROUP BY/HAVING 可以很容易确定重复的行。假设需要创建惟一索引的列为column,对column用group by分组统计并返回每组的个数,如果组中记录数超过1个就存在重复的行。命令如下:

SELECT
  *
FROM table
WHERE rowid IN (SELECT
    MAX(rowid)
  FROM table
  GROUP BY column1,column2
  HAVING COUNT(1) > 1);
-- column1,column2为判断重复的字段

这种查询方式简便、快捷,是ORACLE数据库中最常用的一种方法。
<h3>2.利用伪列自关联查询</h3>

在ORACLE数据库的内部,每一表都有一rowid伪列,行标识惟一标识行,提供对特殊行的快速存取。对该列使用最大(max)或者最小(min)函数可以非常容易地确定重复的行。

1)利用max函数查找重复行

SELECT
  *
FROM table_name a
WHERE rowid < (SELECT
    MAX(rowid)
  FROM table_name
  WHERE column1 = a.column1 AND column2 = a.column2
  AND colum3 = a.colum3);

2)利用min函数查找重复行

SELECT
  *
FROM table_name a
WHERE rowid > (SELECT
    MIN(rowid)
  FROM table_name
  WHERE column1 = a.column1 AND column2 = a.column2
  AND colum3 = a.colum3);

不过,当表比较大(例如50万条以上)时,这个方法的效率之差令人无法忍受。
<h3>3.通过定义完整性约束查找重复行</h3>
定义一个完整性约束,integrity constraint是一个限制基表中一列或多列值的规则。可通过对表定义UNIQUE约束,指定惟一关键字。为了满足此约束,在惟一关键字列中不能包含相同的值。因此可用EXCEPTIONS INTO子句,将违背激活的完整性约束的记录存储在一个表(EXCEPTIONS)中,此表必须在使用此选项之前先建好。将EXCEPTIONS表和table_name表通过rowid关联起来即可得到表table_name中重复的记录。 具体方法如下:

1)创建表EXCEPTIONS,用来存放重复记录的信息。

create table exceptions(
  row_id rowid,
  owner varchar2(30),
  table_name varchar2(30),
  constraint varchar2(30)
);

2)为表table_name定义惟一(UNIQUE)约束,如果在定义的关键字中包含相同的值,系统将提示ORA-02299: 不能创建 - 有重复的值,并将重复记录的信息存入EXCEPTIONS表中。

3)将表table_name与EXCEPTIONS通过伪列(rowid)建立关联,伪列相等的记录就是table_name中的重复记录。

select column1,column2
from table_name a ,EXCEPTIONS b
where a.rowid=b.row_id;

这种方式查询效率较高,而且可以较完全的记录下重复记录的信息,但是步骤较繁琐。