Oracle delete without disabling 约束

Oracle delete without disabling constraint

我正在使用 Oracle 11g。我是一名具有基本 SQL 知识的开发人员。 (:S)

我需要创建一个删除查询,但我的数据库用户没有禁用约束的权限。

我有以下结构。

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 中删除具有 "service=10" 类型服务的所有数据。所以我会删除 卡片,其他与持卡人 相关的 table,为简洁起见我没有在此处显示,最后 CARD_HOLDER_SERVICESCARD_HOLDER 本身。

问题是,为了删除持卡人,我需要知道它是否有 service=10,如果我删除 CARD_HOLDER_SERVICES首先我没有那个信息来过滤我需要删除的持卡人。

我在 table CARD_HOLDER_SERVICES 中检查了 CARD_HOLDER_ID 约束的类型 NOT DEFERRABLE

我唯一能想到但我不知道该怎么做的事情,无论它是否会起作用,就是用 CARD_HOLDER_ID 创建一个临时的 table我想删除,然后删除 CARD_HOLDER_SERVICES 最后 CARD_HOLDER.

谁能告诉我最简单最好的方法是什么?

性能不是问题。

提前致谢。

根据数据量和性能要求,我可能只写一些程序代码。如果我了解您的要求,例如

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;

我建议您使用集合(最多可以说 50-80k 条记录)。

所以先取card_holder_id到collection中,在我的例子中是c_serv,然后根据这个id做delete语句。如果使用 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;

注意,我假设卡片table包含card_holder_id,您可以根据您的设计进行调整,例如相反,如果 card_holder 中有 card_id,则将 delete from card 替换为

DELETE FROM card WHERE card_id in 
 (select card_id from card_holder where card_holder_id=c_serv(i)).