oracle - 如何根据表 FK 关系在 PL/SQL 中生成 DELETE 语句?

标签 oracle plsql code-generation

是否可以通过脚本/工具使用 Oracle PL/SQL 基于表 fk 关系自动生成许多删除语句?

在示例中:我有表:CHICKEN (CHICKEN_CODE NUMBER) 并且有 30 个表对其 CHICKEN_CODE 的 fk 引用,我需要删除;还有其他 150 个表外键链接到我需要先删除的 30 个表。

是否有一些我可以运行的工具/脚本 PL/SQL,以便根据 FK 关系为我生成所有必要的删除语句?

(顺便说一句,我知道关系上的级联删除,但请注意:我不能在我的生产数据库中使用它,因为它很危险!)

我正在使用 Oracle 数据库 10G R2。

请注意这一点:

Generate Delete Statement From Foreign Key Relationships in SQL 2008?

另一个用户刚刚在 SQL SERVER 2008 中编写它,任何人都可以转换为 Oracle 10G PL/SQL?
我不能... :-(

请假设 V_CHICKEN 和 V_NATION 是从根表中选择要删除的 CHICKEN 的条件:条件是:根表上的“其中 COD_CHICKEN = V_CHICKEN AND COD_NATION = V_NATION”。

最佳答案

(我的第一个答案变得太长且难以编辑,并且得到了社区维基化,这真的很烦人。这是脚本的最新版本。)

此脚本尝试通过递归执行级联删除。当存在循环引用时,应避免无限循环。但它要求所有循环引用约束都具有 ON DELETE SET NULLON DELETE CASCADE .

CREATE OR REPLACE PROCEDURE delete_cascade(
    table_owner          VARCHAR2,
    parent_table         VARCHAR2,
    where_clause         VARCHAR2
) IS
    /*   Example call:  execute delete_cascade('MY_SCHEMA', 'MY_MASTER', 'where ID=1'); */

    child_cons     VARCHAR2(30);
    parent_cons    VARCHAR2(30);
    child_table    VARCHAR2(30);
    child_cols     VARCHAR(500);
    parent_cols    VARCHAR(500);
    delete_command VARCHAR(10000);
    new_where_clause VARCHAR2(10000);

    /* gets the foreign key constraints on other tables which depend on columns in parent_table */
    CURSOR cons_cursor IS
        SELECT owner, constraint_name, r_constraint_name, table_name, delete_rule
          FROM all_constraints
         WHERE constraint_type = 'R'
           AND delete_rule = 'NO ACTION'
           AND r_constraint_name IN (SELECT constraint_name
                                       FROM all_constraints
                                      WHERE constraint_type IN ('P', 'U')
                                        AND table_name = parent_table
                                        AND owner = table_owner)
           AND NOT table_name = parent_table; -- ignore self-referencing constraints


    /* for the current constraint, gets the child columns and corresponding parent columns */
    CURSOR columns_cursor IS
        SELECT cc1.column_name AS child_col, cc2.column_name AS parent_col
          FROM all_cons_columns cc1, all_cons_columns cc2
         WHERE cc1.constraint_name = child_cons
           AND cc1.table_name = child_table
           AND cc2.constraint_name = parent_cons
           AND cc1.position = cc2.position
        ORDER BY cc1.position;
BEGIN
    /* loops through all the constraints which refer back to parent_table */
    FOR cons IN cons_cursor LOOP
        child_cons   := cons.constraint_name;
        parent_cons  := cons.r_constraint_name;
        child_table  := cons.table_name;
        child_cols   := '';
        parent_cols  := '';

        /* loops through the child/parent column pairs, building the column lists of the DELETE statement */
        FOR cols IN columns_cursor LOOP
            IF child_cols IS NULL THEN
                child_cols  := cols.child_col;
            ELSE
                child_cols  := child_cols || ', ' || cols.child_col;
            END IF;

            IF parent_cols IS NULL THEN
                parent_cols  := cols.parent_col;
            ELSE
                parent_cols  := parent_cols || ', ' || cols.parent_col;
            END IF;
        END LOOP;

        /* construct the WHERE clause of the delete statement, including a subquery to get the related parent rows */
        new_where_clause  :=
            'where (' || child_cols || ') in (select ' || parent_cols || ' from ' || table_owner || '.' || parent_table ||
            ' ' || where_clause || ')';

        delete_cascade(cons.owner, child_table, new_where_clause);
    END LOOP;

    /* construct the delete statement for the current table */
    delete_command  := 'delete from ' || table_owner || '.' || parent_table || ' ' || where_clause;

    -- this just prints the delete command
    DBMS_OUTPUT.put_line(delete_command || ';');

    -- uncomment if you want to actually execute it:
    --EXECUTE IMMEDIATE delete_command;

    -- remember to issue a COMMIT (not included here, for safety)
END;

关于oracle - 如何根据表 FK 关系在 PL/SQL 中生成 DELETE 语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2677081/

相关文章:

oracle - ORA-02303 : cannot drop or replace a type with type or table dependents

java - 从 java 调用 SQLLoader,加载名称包含 @ 符号的文件时出现问题

oracle - 如何在 SQLFiddle 中获取 PL/SQL?

oracle - 在 Oracle Forms 中评估 PL/SQL boolean 变量

c++ - 强制为模板参数类实现函数?

使用 Oracle 11g 的 Oracle 开发人员 VM

Oracle 断开连接,尽管它有足够的进程/ session

oracle - 我如何才能等到所有调度程序作业完成?

java - Spring Roo 的替代用法

c# - netstandard 代码生成器 Microsoft.Data.SqlClient 抛出 FileNotFound System.Security.Principal.Windows,Version=4.1.1.0