Il peut y avoir un outil qui le fait déjà, mais extraire arbitrairement toutes les tables de lignes d'une table de départ est une petite tâche de développement en soi. Je ne peux pas tout écrire pour vous, mais je peux vous aider à démarrer - j'ai commencé à l'écrire, mais après environ 20 minutes, j'ai réalisé que c'était un peu plus de travail que je voulais consacrer à une réponse non rémunérée.
Je peux voir que cela est mieux fait par une procédure PL/SQL récursive qui utiliserait dbms_ouput et user_cons_columns &user_constraints pour créer une instruction d'insertion pour la table source. Vous pouvez tricher un peu en écrivant toutes les insertions comme si les colonnes étaient des valeurs char, car Oracle convertira implicitement toutes les valeurs char dans le bon type de données, en supposant que vos paramètres NLS sont identiques sur le système source et cible.
Notez que le package ci-dessous aura des problèmes si vous avez des relations circulaires dans vos tables ; également, sur les versions antérieures d'Oracle, vous pouvez manquer d'espace tampon avec dbms_output. Les deux problèmes peuvent être résolus en insérant le sql généré dans une table intermédiaire qui a un index unique sur le sql, et en annulant la récursivité si vous obtenez une collision de clé unique. Le gros gain de temps ci-dessous est la fonction MakeParamList, qui convertit un curseur qui renvoie une liste de colonnes soit en une liste séparée par des virgules, soit en une seule expression qui affichera les valeurs de ces colonnes sous une forme entre guillemets et séparées par des virgules lorsqu'elle est exécutée en tant que clause select dans une requête sur la table.
Notez également que le package suivant ne fonctionnera pas vraiment tant que vous ne le modifierez pas davantage (l'une des raisons pour lesquelles j'ai arrêté de l'écrire) :l'instruction d'insertion initiale générée est basée sur l'hypothèse que l'argument restrict_vals transmis entraînera la création d'une seule ligne généré - bien sûr, ce n'est presque certainement pas le cas une fois que vous commencez la récurrence (puisque vous aurez de nombreuses lignes enfants pour un parent). Vous devrez modifier la génération de la première instruction (et des appels récursifs suivants) pour qu'elle soit à l'intérieur d'une boucle afin de gérer les cas où l'appel au premier appel EXECUTE IMMEDIATE génère plusieurs lignes au lieu d'une seule. Les bases pour le faire fonctionner sont ici, il vous suffit de peaufiner les détails et de faire fonctionner le curseur externe.
Une dernière note également :il est peu probable que vous puissiez exécuter cette procédure pour générer un ensemble de lignes qui, une fois insérées dans un système cible, donneraient un ensemble de données « propres », car même si vous obtiendriez toutes les données dépendantes, cela les données peuvent dépendre d'autres tables que vous n'avez pas importées (par exemple, la première table enfant que vous rencontrez peut avoir d'autres clés étrangères qui pointent vers des tables sans rapport avec votre table initiale). Dans ce cas, vous voudrez peut-être commencer par les tables détaillées et progresser vers le haut plutôt que vers le bas ; ce faisant, vous voudriez également inverser l'ordre des instructions que vous avez générées, soit à l'aide d'un utilitaire de script, soit en insérant le sql dans une table intermédiaire comme je l'ai mentionné ci-dessus, avec une séquence, puis en le sélectionnant avec un tri décroissant .
Pour l'invoquer, vous transmettez la liste de colonnes séparées par des virgules à contraindre en tant que Constraint_cols et la liste de valeurs correspondantes séparées par des virgules en tant que Constraint_vals, par exemple :
exec Data_extractor.MakeInserts ('MYTABLE', 'COL1, COL2', '99, 105')
Le voici :
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;