Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Mengekstrak baris dari DB termasuk baris dependen

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;


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Perlu memangkas ruang kosong di Oracle

  2. Cara mengganti nama prosedur Oracle

  3. ORA-00936 ekspresi yang hilang

  4. c# Entity Framework EF 4.1 Ubah Skema dan nama Database saat runtime

  5. Kelompokkan menurut untuk membuat perpaduan vertikal