2010-01-08 5 views
3

Предполагая, что все внешние ключи имеют соответствующее ограничение, существует ли простой оператор SQL для удаления строк, не связанных нигде в БД?SQL delete orphan

Что-то простое, как delete from the_table, которое просто пропускает любые строки с дочерней записью?

Я пытаюсь избежать ручного перебора через стол или добавления чего-то вроде where the_SK not in (a,b,c,d).

ответ

6

Вы можете быть в состоянии использовать расширенный DELETE заявление в 10g, которая включает в себя регистрацию ошибок.

Первого использование DBMS_ERRLOG создать протоколирование таблицу (которая является просто копией исходной таблицы с некоторыми дополнительными префиксами столбцами: ORA_ERR_MESG$, ..., ORA_ERR_TAG$)

execute dbms_errlog.create_error_log('parent', 'parent_errlog'); 

Теперь вы можете использовать пункт LOG погрешности ВЕЯТ чтобы захватить все строки, которые существующие ограничения целостности:

delete from parent 
    log errors into parent_errlog ('holding-breath') 
    reject limit unlimited; 

в этом случае «держит дыхание» комментарий будет идти в ORA_ERR_TAG$ колонки.

Вы можете прочитать полную документацию here.

Если родительский стол огромен, и вы только хотите удалить несколько паразитных строк, вы получите таблицу parent_errlog, которая по существу является дубликатом вашей таблицы parent. Если это не нормально, вы должны будете сделать это долгий путь:

  1. Непосредственно ссылаться на дочерние таблицы (следующие Tony's solution), или,
  2. Петля через таблицу в PL/SQL и поймать любой исключения (следующие Confusion's и Bob's solutions).
+0

Ничего, я не знал об этой регистрации ошибок. Таким образом, мне не нужно указывать ни одного ребенка, ни цикл через строки, но я думаю, что вы должны были добавить «запретить лимит неограниченно» (или любой другой номер). Как бы то ни было, удаление все еще не выполняется. – RichN

+0

Хорошо заметили - добавили к моему ответу –

1

Нет. Очевидно, что вы можете сделать это (но я не понимаю, вы предпочли бы):

delete parent 
where not exists (select null from child1 where child1.parent_id = parent.parent_id) 
and not exists (select null from child2 where child2.parent_id = parent.parent_id) 
... 
and not exists (select null from childn where childn.parent_id = parent.parent_id); 
2

Самый простой способ - написать приложение или хранимую процедуру, которая пытается удалить строки в таблице поочередно и просто игнорировать сбои из-за ограничений внешнего ключа. Впоследствии все строки, не имеющие ограничения внешнего ключа, должны быть удалены. В зависимости от требуемой/возможной производительности это может быть вариант.

1

Один из способов сделать это, чтобы написать что-то вроде следующего:

eForeign_key_violation EXCEPTION; 
PRAGMA EXCEPTION_INIT(eForeign_key_violation, -2292); 

FOR aRow IN (SELECT primary_key_field FROM A_TABLE) LOOP 
    BEGIN 
    DELETE FROM A_TABLE A 
    WHERE A.PRIMARY_KEY_FIELD = aRow.PRIMARY_KEY_FIELD; 
    EXCEPTION 
    WHEN eForeign_key_violation THEN 
     NULL; -- ignore the error 
    END; 
END LOOP; 

Если ребенок строка существует УДАЛИТЬ потерпит неудачу и строки не будут удалены, и вы можете перейти к следующему ключу.

Обратите внимание, что если ваш стол большой, это может занять некоторое время.