Det kan finnas något verktyg som redan gör det, men att godtyckligt extrahera alla radtabeller från en starttabell är en liten utvecklingsuppgift i sig. Jag kan inte skriva hela grejen åt dig, men jag kan få dig igång - jag började skriva det, men efter ungefär 20 minuter insåg jag att det var lite mer arbete som jag ville ägna mig åt ett obetalt svar.
Jag kan se att det görs bäst av en rekursiv PL/SQL-procedur som skulle använda dbms_ouput och user_cons_columns &user_constraints för att skapa inserts-sats för källtabellen. Du kan fuska lite genom att skriva alla infogningar som om kolumnerna vore char-värden, eftersom Oracle implicit kommer att konvertera alla char-värden till rätt datatyp, förutsatt att dina NLS-parametrar är identiska på käll- och målsystemet.
Observera att paketet nedan kommer att få problem om du har cirkulära relationer i dina tabeller; På tidigare versioner av Oracle kan du också få slut på buffertutrymme med dbms_output. Båda problemen kan lösas genom att infoga den genererade SQL-filen i en staging-tabell som har ett unikt index på SQL-filen, och avbryta rekursionen om du får en unik nyckelkollision. Den stora tidsbesparingen nedan är MakeParamList-funktionen, som konverterar en markör som returnerar en lista med kolumner till antingen en kommaseparerad lista eller ett enstaka uttryck som visar värdena för dessa kolumner i en form med citattecken, kommaseparerad form när den körs som välj sats i en fråga mot tabellen.
Observera också att följande paket inte riktigt kommer att fungera förrän du modifierar det ytterligare (en av anledningarna till att jag slutade skriva det):Den initiala infogningssatsen som genereras är baserad på antagandet att argumentet constraint_vals som skickas in kommer att resultera i att en enda rad blir genereras - naturligtvis är detta nästan säkert inte fallet när du börjar återkommande (eftersom du kommer att ha många barnrader för en förälder). Du måste ändra genereringen av den första satsen (och de efterföljande rekursiva anropen) till att vara inne i en loop för att hantera de fall där anropet till det första EXECUTE IMMEDIATE-anropet genererar flera rader istället för en enda. Grunderna för att få det att fungera är här, du behöver bara slipa ut detaljerna och få den yttre markören att fungera.
En sista anmärkning också:Det är osannolikt att du skulle kunna köra den här proceduren för att generera en uppsättning rader som, när de infogas i ett målsystem, skulle resultera i en "ren" uppsättning data, eftersom även om du skulle få alla beroende data, data kan bero på andra tabeller som du inte importerade (t.ex. den första underordnade tabellen du stöter på kan ha andra främmande nycklar som pekar på tabeller som inte är relaterade till din ursprungliga tabell). I så fall kanske du vill börja med detaljtabellerna och arbeta dig uppåt istället för nedåt; Om du gör det, skulle du också vilja vända ordningen till de satser du genererade, antingen med hjälp av ett skriptverktyg eller genom att infoga sql i en mellanställningstabell som jag nämnde ovan, med en sekvens och sedan välja ut den med fallande sortering .
När det gäller att anropa den skickar du den kommaseparerade listan med kolumner för att begränsa som constraint_cols och motsvarande kommaseparerade lista med värden som constraint_vals, t.ex.:
exec Data_extractor.MakeInserts ('MYTABLE', 'COL1, COL2', '99, 105')
Här är 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;