Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Wyodrębnianie wierszy z bazy danych, w tym wierszy zależnych

Może istnieć jakieś narzędzie, które już to robi, ale arbitralne wyodrębnienie wszystkich tabel wierszy z tabeli początkowej jest samo w sobie małym zadaniem programistycznym. Nie mogę napisać za ciebie całej rzeczy, ale mogę zacząć – zacząłem to pisać, ale po około 20 minutach zdałem sobie sprawę, że to trochę więcej pracy, którą chciałem poświęcić na bezpłatną odpowiedź.

Widzę, że najlepiej to robi rekurencyjna procedura PL/SQL, która używa dbms_ouput i user_cons_columns i user_constraints do tworzenia instrukcji inserts dla tabeli źródłowej. Możesz trochę oszukać, pisząc wszystkie wstawki tak, jakby kolumny były wartościami znaków, ponieważ Oracle domyślnie skonwertuje dowolne wartości znaków na właściwy typ danych, zakładając, że parametry NLS są identyczne w systemie źródłowym i docelowym.

Zauważ, że poniższy pakiet będzie sprawiał problemy, jeśli masz w tabelach relacje kołowe; ponadto we wcześniejszych wersjach Oracle może zabraknąć miejsca w buforze za pomocą polecenia dbms_output. Oba problemy można rozwiązać, wstawiając wygenerowany sql do tabeli pomostowej, która ma unikalny indeks na sql, i przerwać rekurencję, jeśli wystąpi kolizja unikatowego klucza. Największą oszczędnością czasu poniżej jest funkcja MakeParamList, która konwertuje kursor zwracający listę kolumn na listę oddzieloną przecinkami lub na pojedyncze wyrażenie, które wyświetli wartości tych kolumn w postaci cudzysłowu, oddzielone przecinkami, gdy są uruchamiane jako select klauzula w zapytaniu względem tabeli.

Zauważ również, że poniższy pakiet nie będzie działał, dopóki nie zmodyfikujesz go dalej (jeden z powodów, dla których przestałem go pisać):Wygenerowana początkowa instrukcja wstawiania jest oparta na założeniu, że przekazany argument ograniczenia_wartości spowoduje, że zostanie wyświetlony pojedynczy wiersz generowane - oczywiście prawie na pewno nie ma to miejsca, gdy zaczniesz rekursywnie (ponieważ będziesz mieć wiele wierszy podrzędnych dla rodzica). Będziesz musiał zmienić generację pierwszej instrukcji (i kolejnych wywołań rekurencyjnych), aby znajdowała się w pętli, aby obsłużyć przypadki, w których wywołanie pierwszego wywołania EXECUTE IMMEDIATE generuje wiele wierszy zamiast jednego. Podstawy działania są tutaj, wystarczy wyszlifować szczegóły i uruchomić zewnętrzny kursor.

Jeszcze jedna uwaga końcowa:jest mało prawdopodobne, abyś mógł uruchomić tę procedurę w celu wygenerowania zestawu wierszy, które po wstawieniu do systemu docelowego dałyby „czysty” zestaw danych, ponieważ chociaż uzyskasz wszystkie dane zależne, to dane mogą zależeć od innych tabel, których nie zaimportowałeś (np. pierwsza napotkana tabela podrzędna może mieć inne klucze obce, które wskazują na tabele niezwiązane z tabelą początkową). W takim przypadku możesz zacząć od tabel szczegółów i poruszać się w górę zamiast w dół; robiąc to, chciałbyś również odwrócić kolejność do wygenerowanych instrukcji, używając narzędzia skryptowego lub wstawiając sql do tabeli pomostowej, jak wspomniałem powyżej, z sekwencją, a następnie wybierając ją z sortowaniem malejącym .

Jeśli chodzi o jego wywołanie, przekazujesz oddzieloną przecinkami listę kolumn do ograniczenia jako ograniczenia_kolumny i odpowiednią listę wartości oddzielonych przecinkami jako wartości_ograniczeń, np.:

exec Data_extractor.MakeInserts ('MYTABLE', 'COL1, COL2', '99, 105')

Oto on:

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. Jak zainstalować ruby-oci8?

  2. Maskowanie danych Oracle

  3. Procedura Oracle PL/SQL działa wolniej niż SQL

  4. Wiosenna hibernacja JPA:wolne zapytanie SELECT

  5. Wykonaj instrukcję sql przez JDBC z wiązaniem CLOB