Export/Import PL/SQL
DBA's Dictionary |
Поиск идентичных строкПосле массированной загрузки данных в БД из внешних источников часто возникает ситуация, когда необходимо найти дубликаты строк, которые препятствуют созданию уникального или первичного ключа на таблице. Существует несколько вариантов решения этой задачи.
SQL> desc docs
Name Null? Type
--------------------------- -------- --------------
DOC_ID NOT NULL NUMBER(10)
BILL_ID NOT NULL NUMBER(10)
STATUS NOT NULL CHAR(1)
DOC_TYPE NOT NULL CHAR(2)
INVOICE_NUM VARCHAR2(20)
SQL>
SQL> select count(*) from docs;
COUNT(*)
---------
2625004
SQL>
SQL> set timing on
SQL> alter table docs add constraint pk_docs primary key (doc_id);
alter table docs add constraint pk_docs primary key (doc_id)
*
ERROR at line 1:
ORA-02437: cannot validate (EDWARD.PK_DOCS) - primary key violated
real: 56150
SQL>
Вариант 1Наверное наиболее логичный и интуитивно понятный способ - сделать группировку по столбцу.
SQL> select doc_id, count(*)
2 from docs
3 group by doc_id
4 having count(*) > 1;
DOC_ID COUNT(*)
--------- ---------
53470 2
1170094 2
2153448 2
2845200 2
real: 62049
OPERATION OPTIONS OBJECT_NAME ID PARENT_ID COST CARDINALITY BYTES
----------------- --------- ----------- -- --------- ------ ----------- ---------
SELECT STATEMENT 0 10274 131250 656250
FILTER 1 0
SORT GROUP BY 2 1 10274 131250 656250
TABLE ACCESS FULL DOCS 3 2 1701 2625004 13125020
Недостаток этого метода в том, что он не дает значения ROWID строк, а значит нужен дополнительный full table scan для последующего удаления дубликатов. Вариант 2Этот вариант использует тот факт, что ROWID уникален для любой строки в пределах таблицы. SQL> select doc_id, rowid 2 from docs d1 3 where rowid > (select min(rowid) 4 from docs d2 5 where d2.doc_id = d1.doc_id) OPERATION OPTIONS OBJECT_NAME ID PARENT_ID COST CARDINALITY BYTES ----------------- ---------- ------------ --- --------- ----- ----------- --------- SELECT STATEMENT 0 1701 131251 1575012 FILTER 1 0 TABLE ACCESS FULL DOCS 2 1 1701 131251 1575012 SORT AGGREGATE 3 1 1 12 TABLE ACCESS FULL DOCS 4 3 1701 2 24 Для такой большой таблицы (2625004 строк) этот запрос будет отрабатывать часы. Я не советую применять его на больших таблицах. Вариант 3Использует возможности, предоставляемые Oracle для проверки уникальности ключа. SQL> desc exceptions Name Null? Type -------------- -------- -------------- ROW_ID ROWID OWNER VARCHAR2(30) TABLE_NAME VARCHAR2(30) CONSTRAINT VARCHAR2(30) Вы можете переименовать эту таблицу по своему желанию 2. Получение ROWID строк, вызывающих нарушение уникальности ключа.
SQL> alter table DOCS add constraint PK_DOCS primary key (DOC_ID)
2 exceptions into EXCEPTIONS;
alter table DOCS add constraint PK_DOCS primary key (DOC_ID)
*
ERROR at line 1:
ORA-02437: cannot validate (EDWARD.PK_DOCS) - primary key violated
real: 204695
SQL>
SQL> select d.doc_id
2 from docs d, exceptions e
3 where d.rowid = e.row_id and
4 e.constraint = 'PK_DOCS'
5 order by d.doc_id;
DOC_ID
---------
53470
53470
1170094
1170094
2153448
2153448
2845200
2845200
8 rows selected.
real: 491
ЗаключениеВариант 1 и Вариант 2 пригодны для поиска дупликатов строк в небольших таблицах. Вариант 3 - универсален. Last Update: October 11, 2007 18:33:32
|