从相关表中删除记录

时间:2014-04-02 18:29:13

标签: sql oracle plsql

我有两张桌子:

  • 报告
  • report_contents

报告表中的外键 content_id 相关。

我需要创建删除一些报告及其内容的程序,如下所示:

DELETE FROM report_contents WHERE id IN 
     (SELECT content_id FROM reports WHERE extra_value = extraValue)

DELETE FROM reports WHERE extra_value = extraValue

但首先无法从 report_contents 表中删除记录,因为报告表上的 content_id 列存在约束。

另一方面,当我首先从报告表中删除记录时,我不知道应该删除哪些report_contents ...

CREATE OR REPLACE PROCEDURE delete_reports (extraValue NUMBER) IS
BEGIN
/* removing reports with extra_value = extraValue */
/* removing their report_contents */
END;

最好的方法是什么? (我不想在删除级联约束上添加

3 个答案:

答案 0 :(得分:1)

如果id的数量相对较小(即只有几百或几千),您可以在PL / SQL数组中轻松存储要暂时删除的ID。

PROCEDURE delete_reports (extraValue NUMBER) IS
  TYPE id_table IS TABLE OF reports.content_id%TYPE INDEX BY BINARY_INTEGER;
  ids id_table;

BEGIN

  /* which reports to delete? */
  SELECT content_id BULK COLLECT INTO ids
  FROM reports WHERE extra_value = p_extra_value;

  /* removing reports with extra_value = extraValue */
  DELETE reports WHERE extra_value = p_extra_value;

  /* removing their report_contents */
  FORALL i IN 1..ids.COUNT
    DELETE report_contents WHERE id = ids(i);

END delete_reports;

如果id的数量很大(例如数百万或更多),那么我可能会将其分解为循环并批量获取ID。

答案 1 :(得分:0)

由于它是SP,您可以使用中间TABLE变量来存储结果

CREATE OR REPLACE PROCEDURE delete_reports (extraValue NUMBER) IS
BEGIN
    DECLARE @TABLE table
    ( CONTENT_ID int)

    INSERT INTo @TABLE
    SELECT content_id FROM reports WHERE extra_value = extraValue

    DELETE FROM reports B WHERE EXISTS (SELECT * FROM @TABLE A WHERE A.Content_id=B.Content_id)

    DELETE FROM report_contents C WHERE EXISTS (SELECT * FROM @TABLE A WHERE A.Content_id=C.ID)
END

我假设你可以从两个标签中使用CONTENT_IDdelete

答案 2 :(得分:0)

编辑:感谢有用的评论者,他指出了我的原始解决方案如何在CONTENT_ID表的REPORTSID之间留下关系。 REPORT_CONTENT表。我第一次尝试的游标查询假设REPORT_CONTENT表中的任何孤立ID都是删除的理想候选者。这个假设是不可支持的,所以我将光标重写为下面两个不同的游标。


我认为原帖是关于如何在 ORACLE 中执行此操作的问题?这是使用Oracle PL / SQL CURSOR的替代方法。

 CREATE or REPLACE PROCEDURE proc_delete_reports ( p_extra_value in varchar2 )
    is

    CURSOR del_reports is
       SELECT content_id FROM reports WHERE extra_value = p_extra_value
          FOR UPDATE;

    CURSOR del_contents (p_content_id IN number) is
       SELECT id
         FROM report_contents
        WHERE id = p_content_id 
          FOR UPDATE;

 BEGIN
    FOR i in del_reports
      LOOP

      DELETE FROM reports
       WHERE current of del_reports;

      FOR j in del_contents(p_content_id => i.content_id)
        LOOP

        DELETE from report_contents
        WHERE current of del_contents;
      END LOOP;

    END LOOP;
    COMMIT;

 END proc_delete_reports;

给定适当的语法,您可以在遍历循环中的每个值时修改游标输出的内容。