Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 从相关表中删除记录_Sql_Oracle_Plsql - Fatal编程技术网

Sql 从相关表中删除记录

Sql 从相关表中删除记录,sql,oracle,plsql,Sql,Oracle,Plsql,我有两张桌子: 报告 报告内容 在报告表上,通过外键内容id关联 我需要创建删除一些报告及其内容的过程,如下所示: DELETE FROM report_contents WHERE id IN (SELECT content_id FROM reports WHERE extra_value = extraValue) DELETE FROM reports WHERE extra_value = extraValue 但是不可能首先从报告内容表中删除记录,因为报告表上的内

我有两张桌子:

  • 报告
  • 报告内容
报告表上,通过外键内容id关联

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

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

DELETE FROM reports WHERE extra_value = extraValue
但是不可能首先从报告内容表中删除记录,因为报告表上的内容id列有约束

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

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

最好的方法是什么?(我不想添加delete cascade constraint)

因为它是一个
SP
,所以可以使用中间
变量来存储结果

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\u ID
从两个选项卡中
删除
编辑:,这要感谢一位有帮助的评论者,他指出了我最初的解决方案是如何忽略了
报表
表的
CONTENT\u ID
报表内容
表的
ID
之间的关系的。我第一次尝试的游标查询假设
REPORT\u CONTENT
表中的任何孤立ID都是删除的理想候选。这个假设是不可支持的,所以我将游标重写为下面两个不同的游标


我认为最初的帖子是关于如何在ORACLE中做到这一点的问题?下面是使用Oracle PL/SQL游标的另一种方法

 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;

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

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

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。

哪个是父表和子表?@BhupeshC,REPORT\u CONTENTS是父表。报表表有“content\u id”列(外键)。但我需要创建过程delete\u报表(extraValue编号)。可以在过程内部声明表变量吗?@DavidSilva实际上可以-尤其是因为它是
SP
。可以在SP或函数中声明变量,但不能在视图中声明。你可以在网上找到很多关于这个主题的资料。谢谢!您可以展开缩写“SP”吗?SP-存储过程此过程假定每个
报告内容
报告
中始终至少有一行。如果在调用此过程之前,
report\u contents
中有一行在
reports
中没有行,该怎么办?此过程也将删除该记录,即使它与参数
p\u extra\u值
不匹配。