Potrebbe esserci già qualche strumento che lo fa, ma estrarre arbitrariamente tutte le tabelle di righe da una tabella iniziale è di per sé una piccola attività di sviluppo. Non posso scrivere tutto per te, ma posso farti iniziare - ho iniziato a scriverlo, ma dopo circa 20 minuti ho capito che era un po' più di lavoro che volevo impegnarmi per una risposta non pagata.
Posso vedere che viene fatto meglio da una procedura PL/SQL ricorsiva che userebbe dbms_ouput e user_cons_columns &user_constraints per creare l'istruzione inserts per la tabella di origine. Puoi imbrogliare un po' scrivendo tutti gli inserti come se le colonne fossero valori char, poiché Oracle converte implicitamente qualsiasi valore char nel tipo di dati corretto, supponendo che i parametri NLS siano identici sul sistema di origine e di destinazione.
Nota, il pacchetto seguente avrà problemi se hai relazioni circolari nelle tue tabelle; inoltre, nelle versioni precedenti di Oracle, potresti esaurire lo spazio nel buffer con dbms_output. Entrambi i problemi possono essere risolti inserendo lo sql generato in una tabella di staging che ha un indice univoco su sql e interrompendo la ricorsione se si verifica una collisione di chiavi univoche. Il grande risparmio di tempo di seguito è la funzione MakeParamList, che converte un cursore che restituisce un elenco di colonne in un elenco separato da virgole o in una singola espressione che visualizzerà i valori di quelle colonne in una forma separata da virgolette e virgole quando eseguita come selezionare la clausola in una query sulla tabella.
Nota anche che il seguente pacchetto non funzionerà davvero fino a quando non lo modificherai ulteriormente (uno dei motivi per cui ho smesso di scriverlo):l'istruzione di inserimento iniziale generata si basa sul presupposto che l'argomento limit_vals passato risulterà in una singola riga generato - ovviamente, questo non è quasi certamente il caso una volta che inizi a ricorrere (poiché avrai molte righe figlio per un genitore). Sarà necessario modificare la generazione della prima istruzione (e le successive chiamate ricorsive) in modo che si trovi all'interno di un ciclo per gestire i casi in cui la chiamata alla prima chiamata EXECUTE IMMEDIATE genera più righe anziché una singola. Le basi per farlo funzionare sono qui, devi solo rifinire i dettagli e far funzionare il cursore esterno.
Un'ultima nota inoltre:è improbabile che tu possa eseguire questa procedura per generare un insieme di righe che, una volta inserite in un sistema di destinazione, risulteranno in un insieme di dati "pulito", poiché sebbene tu possa ottenere tutti i dati dipendenti, quello i dati possono dipendere da altre tabelle che non hai importato (ad esempio, la prima tabella figlio che incontri potrebbe avere altre chiavi esterne che puntano a tabelle non correlate alla tabella iniziale). In tal caso, potresti voler iniziare con le tabelle dei dettagli e procedere verso l'alto anziché verso il basso; facendo ciò, vorresti anche invertire l'ordine alle istruzioni che hai generato, usando un'utilità di scripting o inserendo sql in una tabella di staging come ho detto sopra, con una sequenza, quindi selezionandola con un ordinamento decrescente .
Per quanto riguarda l'invocazione, si passa l'elenco di colonne separate da virgole da vincolare come vincoli_cols e il corrispondente elenco di valori separati da virgole come vincoli_vals, ad esempio:
exec Data_extractor.MakeInserts ('MYTABLE', 'COL1, COL2', '99, 105')
Eccolo:
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;