How to find and delete duplicate records in Firebird database

DELETE command, as it is defined in SQL standard) always delete all records which satisfy the condition. Usually, we want to delete all duplicates except the one. To do it, we need to use RDB$DB_KEY - an implicit record number in Firebird database.


 DELETE FROM XXX T1 WHERE EXISTS 
  (SELECT * FROM XXX T2 WHERE 
     (T2.column1 = T1.column1 or (T2.column1 is null and T2.column1 is null)) AND 
     (T2.column2 = T1.column2 or (T2.column2 is null and T2.column2 is null)) AND 
     (.......) AND 
     (T2.RDB$DB_KEY > T1.RDB$DB_KEY))

В этом случае используется RDB$DB_KEY - физический номер записи IB. Можно оставить как запись с самым большим DB_KEY, так и с самым меньшим (> или < в последнем условии WHERE). 

Для поиска имеющих какой-либо одинаковый столбец записей обычно используется запрос, похожий на следующий:

SELECT * FROM TABLE T1 
WHERE (SELECT COUNT(*) 
       FROM TABLE T2 
       WHERE T1.FIELD = T2.FIELD) > 1

Однако этот запрос не совсем эффективен. Вместо него выгоднее использовать процедуру, которая будет выполняться намного быстрее: 
(Ann Harrison)

for select field 
    from table 
    group by field 
    having count (field) > 1 
    into :fld 
do 
  begin 
    for select field 
        from table 
        where field = :fld 
        into :fld1 
    do 
      begin 
        suspend; 
      end 
  end

Но хранимая процедура не всегда удобна. Также можно использовать уникальный идентификатор записи RDB$DB_KEY: 
(Josef Marie M. Alba)

SELECT * FROM TABLE T1 
WHERE EXISTS 
   (SELECT FIELD FROM TABLE T2 
    WHERE T1.FIELD = T2.FIELD AND 
          T1.RDB$DB_KEY != T2.RDB$DB_KEY)