2015-04-02 3 views
0

Я использую Oracle 11g. Я разработчик с базовыми знаниями SQL. (: S)Oracle удаляет без ограничения ограничений

Мне нужно создать запрос на удаление, но у моего пользователя БД нет разрешения на отключение ограничений.

У меня есть следующая структура.

TABLE CARD_HOLDER 
CARD_HOLDER_ID 
... (other fields) 

/

TABLE CARD 
Card_ID 
... (other fields) 

/

TABLE SERVICE 
SERVICE_ID 
SERVICE_DESCRIPTION (credit, debit, etc...) 

/

TABLE CARD_HOLDER_SERVICES 
CARD_HOLDER_ID 
SERVICE_ID 
... (other fields) 

нужно удалить все данные из CARD_HOLDERS, которые имеют услугу типа "сервис = 10" , Так что я бы удалить карты, другие таблицы, связанные с держателем карты, что я не показываю здесь ради краткости, и наконец CARD_HOLDER_SERVICES и CARD_HOLDER itselt.

Дело в том, чтобы удалить держатель карты, мне нужно знать, если он имеет обслуживание = 10, и если я удалить CARD_HOLDER_SERVICES первых у меня нет этой информации больше фильтровать которые мне нужно удалить.

Я проверил в таблице CARD_HOLDER_SERVICES что CARD_HOLDER_ID ограничение типа НЕ откладываемые.

Единственное, что я мог думать, делать и я не знаю, как, ни ли это будет работать или нет, не создать временную таблицу с CARD_HOLDER_IDs, которые я хочу удалить, а затем удалить CARD_HOLDER_SERVICES и последним CARD_HOLDER.

Может ли кто-нибудь сказать мне, что является самым простым и лучшим способом сделать это?

Производительность не является проблемой.

Заранее спасибо.

ответ

2

В зависимости от объемов данных и требований к производительности, я бы, вероятно, просто написал некоторый процедурный код. Если я правильно понимаю ваши требования, что-то вроде

BEGIN 
    FOR chs IN (SELECT * 
       FROM card_holder_services 
       WHERE service_id = 10) 
    LOOP 
    FOR ch IN (SELECT * 
       FROM card_holder 
       WHERE card_holder_id = chs.card_holder_id) 
    LOOP 
     DELETE FROM card 
     WHERE card_id = ch.card_id; 
    END LOOP; 

    DELETE FROM card_holder 
    WHERE card_holder_id = chs.card_holder_id; 

    DELETE FROM card_holder_services 
    WHERE card_holder_id = chs.card_holder_id 
     AND service_id  = 10; 

    END LOOP; 
END; 
/

Если вы заинтересованы в чистой эффективности, вы могли бы сделать отдельные DELETE заявления, которые в конечном итоге дублирования изрядное количество кода

DELETE FROM card 
WHERE card_id IN (SELECT ch.card_id 
        FROM card_holder ch 
          JOIN card_holder_services chs 
          ON(ch.card_holder_id = chs.card_holder_id) 
        WHERE chs.service_id = 10); 

DELETE FROM card_holder 
WHERE card_holder_id IN (SELECT card_holder_id 
          FROM card_holder_services chs 
          WHERE chs.service_id = 10); 

DELETE FROM card_holder_services 
WHERE service_id = 10; 
+0

Я не знаю о первом методе процедуры. Но если я попытаюсь удалить card_holder перед card_holder_service, как во втором подходе, это даст мне ошибку ограничения. Потому что он используется. Я попробую процедуру, и как только у меня появится обратная связь, я дам вам знать. –

+0

Я только что адаптировал первый подход к моей реальной схеме и работал как шарм. Для циклов решена моя проблема. Большое спасибо. Извините за задержку с ответом. –

0

Я хотел бы предложить вам использовать коллекцию (до 50-80 тыс. записей).

Итак, сначала заберите card_holder_id в коллекцию, в моем примере c_serv, а затем создайте инструкцию delete в соответствии с этим id. Если вы используете оператор FORALL для циклической сборки, он будет быстрее, чем классический FOR LOOP.

declare 
    type t_c_serv is table of number; 
    c_serv t_c_serv; 
begin 
    select card_holder_id bulk collect into c_serv from card_holder_services where service_id=10; 

    FORALL i IN c_serv.FIRST..c_serv.LAST 
    DELETE FROM card where card_holder_id=c_serv(i); 
    FORALL i IN c_serv.FIRST..c_serv.LAST 
    DELETE FROM card_holder_services where card_holder_id=c_serv(i); 
    FORALL i IN c_serv.FIRST..c_serv.LAST 
    DELETE FROM card_holder where card_holder_id=c_serv(i); 

end; 

Обратите внимание, что я предположил, что карточный стол содержит card_holder_id, вы можете отрегулировать его в соответствии с вашим дизайном, например. если вместо этого есть card_id в card_holder, то замените удаление с карты на

DELETE FROM card WHERE card_id in 
(select card_id from card_holder where card_holder_id=c_serv(i)). 
Смежные вопросы