2010-08-17 5 views
17

У меня есть строки в таблице базы данных Oracle, которые должны быть уникальными для комбинации двух полей, но уникальный ограничитель не настроен в таблице, поэтому мне нужно найти все строки, которые сами нарушают ограничение с помощью SQL. К сожалению, мои скудные навыки SQL не соответствуют задаче.SQL: Как найти дубликаты на основе двух полей?

В моей таблице три столбца, которые имеют значение: entity_id, station_id и obs_year. Для каждой строки комбинация station_id и obs_year должна быть уникальной, и я хочу узнать, есть ли строки, которые нарушают это, очищая их SQL-запросом.

Я попытался следующий SQL (предложенный this previous question), но она не работает для меня (я получаю ORA-00918 столбец двусмысленно определен):

SELECT 
entity_id, station_id, obs_year 
FROM 
mytable t1 
INNER JOIN (
SELECT entity_id, station_id, obs_year FROM mytable 
GROUP BY entity_id, station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 

Может кто-то предложить, что я делаю неправильно , и/или как это решить?

ответ

33
SELECT * 
FROM (
     SELECT t.*, ROW_NUMBER() OVER (PARTITION BY station_id, obs_year ORDER BY entity_id) AS rn 
     FROM mytable t 
     ) 
WHERE rn > 1 
+0

Большое спасибо за этот ответ. К сожалению, когда я запускаю это, я получаю сообщение «ORA-00923: FROM ключевое слово не найдено, где ожидалось». –

+0

@James: попробуйте сейчас – Quassnoi

+0

В mssql in пришлось поместить 'as x' (имя не имеет значения) за Paranthesis FROM(), чтобы заставить его работать. Отличный ответ! – Mafii

2

Re-запись вашего запроса

SELECT 
t1.entity_id, t1.station_id, t1.obs_year 
FROM 
mytable t1 
INNER JOIN (
SELECT entity_id, station_id, obs_year FROM mytable 
GROUP BY entity_id, station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 

Я думаю, что неоднозначная ошибка столбца (ORA-00918) потому, что вы были select ИНГОВ колонны, чьи имена появились и в таблице и подзапросе, но вы не сделали если хотите, от dupes или от mytable (aliased as t1).

1

Не удалось создать новую таблицу, которая включает в себя уникальное ограничение, а затем скопировать данные по строке подряд, игнорируя ошибки?

+0

Да, это хорошая идея, спасибо! BTW Я пытаюсь понять, как создать ограничение на моей таблице, используя аннотации в моем классе сущности (я разработчик Java с использованием JPA/Hibernate), см. Http://stackoverflow.com/questions/3504477/ how-to-define-that-a-combination-of-columns-should-be-a-unique-constraint-using –

2

Изменение 3 поля в начальный выбор будет

SELECT 
t1.entity_id, t1.station_id, t1.obs_year 
10
SELECT entity_id, station_id, obs_year 
FROM mytable t1 
WHERE EXISTS (SELECT 1 from mytable t2 Where 
     t1.station_id = t2.station_id 
     AND t1.obs_year = t2.obs_year 
     AND t1.RowId <> t2.RowId) 
+0

Похоже, мы не сможем сделать это на вид: ORA-01445: не может выбрать ROWID из или образец, представление соединения без таблицы с сохранением ключа – Thyag

1

Вы должны указать таблицу для столбцов в основной выбор. Кроме того, если entity_id является уникальным ключом для mytable и не имеет отношения к поиску дубликатов, вы не должны группировать его в подзапросах dupes.

Try:

SELECT t1.entity_id, t1.station_id, t1.obs_year 
FROM mytable t1 
INNER JOIN (
SELECT station_id, obs_year FROM mytable 
GROUP BY station_id, obs_year HAVING COUNT(*) > 1) dupes 
ON 
t1.station_id = dupes.station_id AND 
t1.obs_year = dupes.obs_year 
+0

Спасибо, Марк, за отзыв о том, что вы не используете entity_id в подзапросе группировки , и для иллюстративного примера. –

0
SELECT * 
FROM (
     SELECT t.*, ROW_NUMBER() OVER (PARTITION BY station_id, obs_year ORDER BY entity_id) AS rn 
     FROM mytable t 
     ) 
WHERE rn > 1 

по Quassnoi является наиболее эффективным для больших таблиц. у меня был этот анализ стоимости:

SELECT a.dist_code, a.book_date, a.book_no 
FROM trn_refil_book a 
WHERE EXISTS (SELECT 1 from trn_refil_book b Where 
     a.dist_code = b.dist_code and a.book_date = b.book_date and a.book_no = b.book_no 
     AND a.RowId <> b.RowId) 
     ; 

дал стоимость 1322341

SELECT a.dist_code, a.book_date, a.book_no 
FROM trn_refil_book a 
INNER JOIN (
SELECT b.dist_code, b.book_date, b.book_no FROM trn_refil_book b 
GROUP BY b.dist_code, b.book_date, b.book_no HAVING COUNT(*) > 1) c 
ON 
a.dist_code = c.dist_code and a.book_date = c.book_date and a.book_no = c.book_no 
; 

дал стоимость 1271699

в то время как

SELECT dist_code, book_date, book_no 
FROM (
     SELECT t.dist_code, t.book_date, t.book_no, ROW_NUMBER() OVER (PARTITION BY t.book_date, t.book_no 
      ORDER BY t.dist_code) AS rn 
     FROM trn_refil_book t 
     ) p 
WHERE p.rn > 1 
; 

дал стоимость

таблица не индексируются ....

+0

правильно отформатируйте свой ответ. – SSP

0
SELECT entity_id, station_id, obs_year 
    FROM mytable 
GROUP BY entity_id, station_id, obs_year 
HAVING COUNT(*) > 1 

Укажите поля для поиска дубликатов на как SELECT, и в GROUP BY.

Он работает с использованием GROUP BY, чтобы найти любые строки, соответствующие любым другим строкам на основе указанных столбцов. HAVING COUNT(*) > 1 говорит, что нас интересуют только любые строки, которые происходят более одного раза (и, следовательно, дублируются)

+0

Hiya, это вполне может решить проблему ... но было бы хорошо, если бы вы могли дать небольшое объяснение о том, как и почему это работает :) Не забывайте, что есть кучи новичков в переполнении стека, и они могут узнайте кое-что из своего опыта - для вас очевидно, что это не так. –

+0

Спасибо Taryn. Он работает с помощью GROUP BY, чтобы найти любые строки, которые соответствуют любым другим строкам на основе указанных столбцов. HAVING COUNT (*)> 1 говорит, что нас интересуют только любые строки, которые происходят более одного раза (и, следовательно, дублируются) – grokster

+0

Привет, не говорите мне (в комментариях). Я знаю SQL, я не прошу меня ... Такое объяснение является «частью вашего полного ответа» ... поэтому, пожалуйста, отредактируйте свой ответ и добавьте его туда. :) –

Смежные вопросы