sql >> Database teknologi >  >> RDS >> Oracle

Hvordan genererer man DELETE-sætninger i PL/SQL, baseret på tabellerne FK-relationer?

(Mit første svar blev for langt og svært at redigere, og det fik Community Wikified, hvilket er rigtig irriterende. Her er den seneste version af scriptet.)

Dette script forsøger at udføre en kaskadende sletning gennem rekursion. Det bør undgå uendelige loops, når der er cirkulære referencer. Men det kræver, at alle cirkulære referentielle begrænsninger har ON DELETE SET NULL eller ON 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;


  1. Kan jeg flette to databaser til én i Mysql, hvis de begge har det samme skema?

  2. FLET:Opdatering af kilde- og måltabeller placeret på separate servere

  3. SQL-afhængighed af en MariaDB/MySQL-database

  4. Skinner - SQLite3::SQLEundtagelse:nær USING:syntaksfejl