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_SERVICES 和 CARD_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)).
我正在使用 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_SERVICES 和 CARD_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)).