SQL: как найти дубликаты на основе двух полей?
У меня есть строки в таблице базы данных Oracle, которая должна быть уникальной для комбинации двух полей, но уникальное ограничение не настроено в таблице, поэтому мне нужно найти все строки, которые нарушают ограничение, используя SQL. К сожалению, мои скудные навыки SQL не справляются с этой задачей.
моя таблица имеет три столбца, которые имеют отношение: entity_id, station_id и obs_year. Для каждой строки комбинация station_id и obs_year должна быть уникальной, и я хочу узнать, есть ли являются строками, которые нарушают это, смывая их с помощью SQL-запроса.
я попробовал следующий SQL (предложенный этот предыдущий вопрос), но это не работает для меня (я получаю неопределенно определенный столбец 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
может кто-нибудь подсказать, что я делаю неправильно и/или как решить эту проблему?
8 ответов
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
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)
перепишите свой запрос
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) была потому, что вы были selecting столбцы, имена которых появились как в таблице, так и в подзапросе, но вы не указали, хотите ли вы этого от dupes или mytable (псевдоним t1).
не могли бы вы создать новую таблицу, включающую уникальное ограничение, а затем скопировать по строкам данных, игнорируя сбои?
вам нужно указать таблицу для столбцов в главном select. Кроме того, предполагая, что entity_id является уникальным ключом для mytable и не имеет отношения к поиску дубликатов, вы не должны группировать его в подзапросе dupes.
попробуй:
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
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
;
дал стоимостью 1021984
таблица не проиндексирована....
  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 чтобы найти любые строки, которые соответствуют любым другим строкам на основе указанных столбцов. 
The HAVING COUNT(*) > 1 говорит, что мы заинтересованы только в том, чтобы видеть любые строки, которые происходят более 1 раза (и поэтому являются дубликатами) 
