Mungkin ada beberapa alat yang sudah melakukannya, tetapi untuk secara sewenang-wenang mengekstrak semua tabel baris dari tabel awal adalah tugas pengembangan kecil itu sendiri. Saya tidak dapat menulis semuanya untuk Anda, tetapi saya dapat membantu Anda memulai - saya mulai menulisnya, tetapi setelah sekitar 20 menit, saya menyadari bahwa ada sedikit pekerjaan yang ingin saya lakukan untuk jawaban yang tidak dibayar.
Saya dapat melihatnya dilakukan paling baik dengan prosedur PL/SQL rekursif yang akan menggunakan dbms_ouput dan user_cons_columns &user_constraints untuk membuat pernyataan sisipan untuk tabel sumber. Anda dapat sedikit curang dengan menulis semua sisipan seolah-olah kolom adalah nilai char, karena Oracle akan secara implisit mengonversi nilai char apa pun ke tipe data yang tepat, dengan asumsi parameter NLS Anda identik pada sistem sumber &target.
Catatan, paket di bawah ini akan bermasalah jika Anda memiliki hubungan melingkar di tabel Anda; juga, pada Oracle versi sebelumnya, Anda mungkin kehabisan ruang buffer dengan dbms_output. Kedua masalah dapat diselesaikan dengan memasukkan sql yang dihasilkan ke dalam tabel staging yang memiliki indeks unik pada sql, dan membatalkan rekursi jika Anda mendapatkan tabrakan kunci yang unik. Penghemat waktu besar di bawah ini adalah fungsi MakeParamList, yang mengonversi kursor yang mengembalikan daftar kolom menjadi daftar yang dipisahkan koma, atau ekspresi tunggal yang akan menampilkan nilai kolom tersebut dalam bentuk yang dipisahkan koma yang dikutip saat dijalankan sebagai pilih klausa dalam kueri terhadap tabel.
Perhatikan juga bahwa paket berikut tidak akan benar-benar berfungsi sampai Anda memodifikasinya lebih lanjut (salah satu alasan saya berhenti menulisnya):Pernyataan penyisipan awal yang dihasilkan didasarkan pada asumsi bahwa argumen constraint_vals yang diteruskan akan menghasilkan satu baris menjadi dihasilkan - tentu saja, ini hampir pasti tidak terjadi setelah Anda mulai berulang (karena Anda akan memiliki banyak baris anak untuk orang tua). Anda harus mengubah pembuatan pernyataan pertama (dan panggilan rekursif berikutnya) agar berada di dalam loop untuk menangani kasus di mana panggilan ke panggilan EXECUTE IMMEDIATE pertama menghasilkan beberapa baris, bukan satu baris. Dasar-dasar untuk membuatnya berfungsi ada di sini, Anda hanya perlu menggiling detailnya dan membuat kursor luar berfungsi.
Satu catatan terakhir juga:Anda tidak mungkin dapat menjalankan prosedur ini untuk menghasilkan satu set baris yang, ketika dimasukkan ke dalam sistem target, akan menghasilkan kumpulan data yang "bersih", karena meskipun Anda akan mendapatkan semua data dependen, itu data mungkin bergantung pada tabel lain yang tidak Anda impor (mis., tabel anak pertama yang Anda temui mungkin memiliki kunci asing lain yang mengarah ke tabel yang tidak terkait dengan tabel awal Anda). Dalam hal ini, Anda mungkin ingin memulai dengan tabel detail dan bekerja dengan cara Anda ke atas, bukan ke bawah; melakukan itu, Anda juga ingin membalik urutan ke pernyataan yang Anda buat, baik menggunakan utilitas skrip, atau dengan memasukkan sql ke tabel pementasan seperti yang saya sebutkan di atas, dengan urutan, lalu memilihnya dengan pengurutan menurun .
Untuk menjalankannya, Anda meneruskan daftar kolom yang dipisahkan koma ke constraint sebagai constraint_cols dan daftar nilai yang dipisahkan koma terkait sebagai constraint_vals, mis.:
exec Data_extractor.MakeInserts ('MYTABLE', 'COL1, COL2', '99, 105')
Ini dia:
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;