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)

измените 3 поля в начальном select на

SELECT
t1.entity_id, t1.station_id, t1.obs_year

перепишите свой запрос

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 раза (и поэтому являются дубликатами)