sql >> Database >  >> RDS >> Oracle

Rijen extraheren uit een database inclusief afhankelijke rijen

Er is misschien een tool die dit al doet, maar om alle rijentabellen willekeurig uit een starttabel te extraheren, is een kleine ontwikkelingstaak op zich. Ik kan niet alles voor je schrijven, maar ik kan je wel op weg helpen - ik begon het te schrijven, maar na ongeveer 20 minuten realiseerde ik me dat het wat meer werk was dat ik me wilde toeleggen op een onbetaald antwoord.

Ik kan zien dat dit het beste wordt gedaan door een recursieve PL/SQL-procedure die dbms_ouput en user_cons_columns &user_constraints zou gebruiken om een ​​inserts-statement voor de brontabel te maken. Je kunt een beetje vals spelen door alle tussenvoegsels te schrijven alsof de kolommen char-waarden zijn, aangezien Oracle impliciet alle char-waarden naar het juiste datatype zal converteren, ervan uitgaande dat je NLS-parameters identiek zijn op het bron- en doelsysteem.

Let op, het onderstaande pakket zal problemen hebben als je circulaire relaties in je tabellen hebt; ook kan het zijn dat u in eerdere versies van Oracle onvoldoende bufferruimte heeft met dbms_output. Beide problemen kunnen worden opgelost door de gegenereerde sql in een staging-tabel in te voegen die een unieke index op de sql heeft, en de recursie af te breken als u een unieke sleutelbotsing krijgt. De grote tijdbesparing hieronder is de MakeParamList-functie, die een cursor converteert die een lijst met kolommen retourneert in een door komma's gescheiden lijst, of een enkele uitdrukking die de waarden van die kolommen in een aanhalingstekens, door komma's gescheiden vorm weergeeft wanneer deze wordt uitgevoerd als de select clausule in een query tegen de tabel.

Merk ook op dat het volgende pakket niet echt zal werken totdat je het verder aanpast (een van de redenen waarom ik gestopt ben met schrijven):De eerste gegenereerde insert-instructie is gebaseerd op de veronderstelling dat het ingevoerde argument constraint_vals zal resulteren in een enkele rij die gegenereerd - dit is natuurlijk vrijwel zeker niet het geval als u eenmaal begint te herhalen (aangezien u veel onderliggende rijen voor een ouder zult hebben). U moet de generatie van de eerste instructie (en de daaropvolgende recursieve aanroepen) wijzigen zodat deze zich in een lus bevinden om de gevallen af ​​te handelen waarin de aanroep van de eerste EXECUTE IMMEDIATE-aanroep meerdere rijen genereert in plaats van een enkele. De basisprincipes om het werkend te krijgen zijn hier, je hoeft alleen maar de details uit te slijpen en de buitenste cursor te laten werken.

Nog een laatste opmerking:het is onwaarschijnlijk dat u deze procedure zou kunnen uitvoeren om een ​​reeks rijen te genereren die, wanneer ze in een doelsysteem worden ingevoegd, zou resulteren in een "schone" set gegevens, aangezien hoewel u alle afhankelijke gegevens zou krijgen, dat gegevens kunnen afhankelijk zijn van andere tabellen die u niet hebt geïmporteerd (bijv. de eerste onderliggende tabel die u tegenkomt, kan andere externe sleutels hebben die verwijzen naar tabellen die geen verband houden met uw oorspronkelijke tabel). In dat geval wil je misschien beginnen met de detailtabellen en naar boven werken in plaats van naar beneden; als je dat doet, wil je ook de volgorde omkeren naar de instructies die je hebt gegenereerd, ofwel met behulp van een scripthulpprogramma, of door de sql in een staging-tabel in te voegen, zoals ik hierboven vermeld, met een reeks, en deze vervolgens te selecteren met een aflopende sortering .

Wat betreft het aanroepen ervan, geef je de door komma's gescheiden lijst met kolommen die moeten worden beperkt door als constraint_cols en de bijbehorende door komma's gescheiden lijst met waarden als constraint_vals, bijvoorbeeld:

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

Hier is het:

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. Tomcat kan gdk_custom.jar niet vinden, Oracle kan het niet maken?

  2. SQLSTATE [HY000] [1045] uitzondering tijdens verbinding met database via 000webhost

  3. wildfly registreert mysql als databron

  4. De verkeerde uitzondering vangen