Der kan være et eller andet værktøj, der allerede gør det, men at vilkårligt udtrække alle rækketabeller fra en starttabel er en lille udviklingsopgave i sig selv. Jeg kan ikke skrive det hele for dig, men jeg kan få dig i gang - jeg begyndte at skrive det, men efter omkring 20 minutter indså jeg, at det var lidt mere arbejde, som jeg ville forpligte mig til et ubetalt svar.
Jeg kan se det gøres bedst ved en rekursiv PL/SQL-procedure, der ville bruge dbms_ouput og user_cons_columns &user_constraints til at oprette inserts-sætning til kildetabellen. Du kan snyde lidt ved at skrive alle inserts, som om kolonnerne var char-værdier, da Oracle implicit vil konvertere alle char-værdier til den rigtige datatype, forudsat at dine NLS-parametre er identiske på kilde- og målsystemet.
Bemærk, pakken nedenfor vil have problemer, hvis du har cirkulære relationer i dine tabeller; også, på tidligere versioner af Oracle, kan du løbe tør for bufferplads med dbms_output. Begge problemer kan løses ved at indsætte den genererede sql i en staging-tabel, der har et unikt indeks på sql, og afbryde rekursionen, hvis du får en unik nøglekollision. Den store tidsbesparelse nedenfor er MakeParamList-funktionen, som konverterer en markør, der returnerer en liste med kolonner til enten en kommasepareret liste eller et enkelt udtryk, der viser værdierne af disse kolonner i en citeret, kommasepareret form, når den køres som vælg klausul i en forespørgsel mod tabellen.
Bemærk også, at den følgende pakke ikke rigtig virker, før du ændrer den yderligere (en af grundene til, at jeg holdt op med at skrive den):Den indledende insert-sætning, der blev genereret, er baseret på den antagelse, at argumentet constraint_vals, der sendes ind, vil resultere i, at en enkelt række bliver genereret - selvfølgelig er dette næsten helt sikkert ikke tilfældet, når du først begynder at gentage (da du vil have mange underordnede rækker til en forælder). Du skal ændre genereringen af den første sætning (og de efterfølgende rekursive opkald) til at være inde i en løkke for at håndtere de tilfælde, hvor opkaldet til det første EXECUTE IMMEDIATE-kald genererer flere rækker i stedet for en enkelt. Det grundlæggende for at få det til at fungere er her, du skal bare skære detaljerne ud og få den ydre markør til at virke.
En sidste bemærkning også:Det er usandsynligt, at du kan køre denne procedure for at generere et sæt rækker, der, når de indsættes i et målsystem, ville resultere i et "rent" sæt data, da selvom du ville få alle afhængige data, data kan afhænge af andre tabeller, som du ikke importerede (f.eks. kan den første underordnede tabel, du støder på, have andre fremmednøgler, der peger på tabeller, der ikke er relateret til din oprindelige tabel). I så fald vil du måske starte med detaljetabellerne og arbejde dig op i stedet for ned; hvis du gør det, vil du også gerne vende rækkefølgen til de sætninger, du genererede, enten ved hjælp af et script-værktøj eller ved at indsætte sql i en iscenesættelsestabel, som jeg nævnte ovenfor, med en sekvens, og derefter vælge den ud med en faldende sortering .
Med hensyn til påberåbelse af det, sender du den kommaseparerede liste over kolonner for at begrænse som constraint_cols og den tilsvarende kommaseparerede liste over værdier som constraint_vals, f.eks.:
exec Data_extractor.MakeInserts ('MYTABLE', 'COL1, COL2', '99, 105')
Her er den:
CREATE OR REPLACE PACKAGE data_extractor
IS
TYPE column_info IS RECORD(
column_name user_tab_columns.column_name%TYPE
);
TYPE column_info_cursor IS REF CURSOR
RETURN column_info;
FUNCTION makeparamlist(
column_info column_info_cursor
, get_values NUMBER
)
RETURN VARCHAR2;
PROCEDURE makeinserts(
source_table VARCHAR2
, constraint_cols VARCHAR2
, constraint_vals VARCHAR2
);
END data_extractor;
CREATE OR REPLACE PACKAGE BODY data_extractor
AS
FUNCTION makeparamlist(
column_info column_info_cursor
, get_values NUMBER
)
RETURN VARCHAR2
AS
BEGIN
DECLARE
column_name user_tab_columns.column_name%TYPE;
tempsql VARCHAR2(4000);
separator VARCHAR2(20);
BEGIN
IF get_values = 1
THEN
separator := ''''''''' || ';
ELSE
separator := '';
END IF;
LOOP
FETCH column_info
INTO column_name;
EXIT WHEN column_info%NOTFOUND;
tempsql := tempsql || separator || column_name;
IF get_values = 1
THEN
separator := ' || '''''', '''''' || ';
ELSE
separator := ', ';
END IF;
END LOOP;
IF get_values = 1
THEN
tempsql := tempsql || ' || ''''''''';
END IF;
RETURN tempsql;
END;
END;
PROCEDURE makeinserts(
source_table VARCHAR2
, constraint_cols VARCHAR2
, constraint_vals VARCHAR2
)
AS
BEGIN
DECLARE
basesql VARCHAR2(4000);
extractsql VARCHAR2(4000);
tempsql VARCHAR2(4000);
valuelist VARCHAR2(4000);
childconstraint_vals VARCHAR2(4000);
BEGIN
SELECT makeparamlist(CURSOR(SELECT column_name
FROM user_tab_columns
WHERE table_name = source_table), 0)
INTO tempsql
FROM DUAL;
basesql := 'INSERT INTO ' || source_table || '(' || tempsql || ') VALUES (';
SELECT makeparamlist(CURSOR(SELECT column_name
FROM user_tab_columns
WHERE table_name = source_table), 1)
INTO tempsql
FROM DUAL;
extractsql := 'SELECT ' || tempsql || ' FROM ' || source_table
|| ' WHERE (' || constraint_cols || ') = (SELECT '
|| constraint_vals || ' FROM DUAL)';
EXECUTE IMMEDIATE extractsql
INTO valuelist;
-- This prints out the insert statement for the root row
DBMS_OUTPUT.put_line(basesql || valuelist || ');');
-- Now we construct the constraint_vals parameter for subsequent calls:
SELECT makeparamlist(CURSOR( SELECT column_name
FROM user_cons_columns ucc
, user_constraints uc
WHERE uc.table_name = source_table
AND ucc.constraint_name = uc.constraint_name
ORDER BY position)
, 1)
INTO tempsql
FROM DUAL;
extractsql := 'SELECT ' || tempsql || ' FROM ' || source_table
|| ' WHERE ' || constraint_cols || ' = ' || constraint_vals;
EXECUTE IMMEDIATE extractsql
INTO childconstraint_vals;
childconstraint_vals := childconstraint_vals;
-- Now iterate over the dependent tables for this table
-- Cursor on this statement:
-- SELECT uc.table_name child_table, uc.constraint_name fk_name
-- FROM user_constraints uc
-- , user_constraints ucp
-- WHERE ucp.table_name = source_table
-- AND uc.r_constraint_name = ucp.constraint_name;
-- For each table in that statement, find the foreign key
-- columns that correspond to the rows
-- in the parent table
-- SELECT column_name
-- FROM user_cons_columns
-- WHERE constraint_name = fk_name
--ORDER BY POSITION;
-- Pass that columns into makeparamlist above to create
-- the constraint_cols argument of the call below:
-- makeinserts(child_table, ChildConstraint_cols, childconstrain_vals);
END;
END;
END data_extractor;