sql >> Database teknologi >  >> RDS >> Oracle

Udtræk af rækker fra en DB inklusive afhængige rækker

Der kan være et eller andet værktøj, der allerede gør det, men at vilkårligt udtrække alle rækketabeller fra en starttabel er en lille udviklingsopgave i sig selv. Jeg kan ikke skrive det hele for dig, men jeg kan få dig i gang - jeg begyndte at skrive det, men efter omkring 20 minutter indså jeg, at det var lidt mere arbejde, som jeg ville forpligte mig til et ubetalt svar.

Jeg kan se det gøres bedst ved en rekursiv PL/SQL-procedure, der ville bruge dbms_ouput og user_cons_columns &user_constraints til at oprette inserts-sætning til kildetabellen. Du kan snyde lidt ved at skrive alle inserts, som om kolonnerne var char-værdier, da Oracle implicit vil konvertere alle char-værdier til den rigtige datatype, forudsat at dine NLS-parametre er identiske på kilde- og målsystemet.

Bemærk, pakken nedenfor vil have problemer, hvis du har cirkulære relationer i dine tabeller; også, på tidligere versioner af Oracle, kan du løbe tør for bufferplads med dbms_output. Begge problemer kan løses ved at indsætte den genererede sql i en staging-tabel, der har et unikt indeks på sql, og afbryde rekursionen, hvis du får en unik nøglekollision. Den store tidsbesparelse nedenfor er MakeParamList-funktionen, som konverterer en markør, der returnerer en liste med kolonner til enten en kommasepareret liste eller et enkelt udtryk, der viser værdierne af disse kolonner i en citeret, kommasepareret form, når den køres som vælg klausul i en forespørgsel mod tabellen.

Bemærk også, at den følgende pakke ikke rigtig virker, før du ændrer den yderligere (en af ​​grundene til, at jeg holdt op med at skrive den):Den indledende insert-sætning, der blev genereret, er baseret på den antagelse, at argumentet constraint_vals, der sendes ind, vil resultere i, at en enkelt række bliver genereret - selvfølgelig er dette næsten helt sikkert ikke tilfældet, når du først begynder at gentage (da du vil have mange underordnede rækker til en forælder). Du skal ændre genereringen af ​​den første sætning (og de efterfølgende rekursive opkald) til at være inde i en løkke for at håndtere de tilfælde, hvor opkaldet til det første EXECUTE IMMEDIATE-kald genererer flere rækker i stedet for en enkelt. Det grundlæggende for at få det til at fungere er her, du skal bare skære detaljerne ud og få den ydre markør til at virke.

En sidste bemærkning også:Det er usandsynligt, at du kan køre denne procedure for at generere et sæt rækker, der, når de indsættes i et målsystem, ville resultere i et "rent" sæt data, da selvom du ville få alle afhængige data, data kan afhænge af andre tabeller, som du ikke importerede (f.eks. kan den første underordnede tabel, du støder på, have andre fremmednøgler, der peger på tabeller, der ikke er relateret til din oprindelige tabel). I så fald vil du måske starte med detaljetabellerne og arbejde dig op i stedet for ned; hvis du gør det, vil du også gerne vende rækkefølgen til de sætninger, du genererede, enten ved hjælp af et script-værktøj eller ved at indsætte sql i en iscenesættelsestabel, som jeg nævnte ovenfor, med en sekvens, og derefter vælge den ud med en faldende sortering .

Med hensyn til påberåbelse af det, sender du den kommaseparerede liste over kolonner for at begrænse som constraint_cols og den tilsvarende kommaseparerede liste over værdier som constraint_vals, f.eks.:

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

Her er den:

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. Rapportering mere detaljeret end normalt – Microsoft Access

  2. MySQL crasher på SQL

  3. Opdater en kolonneværdi til ANTAL rækker for specifikke værdier i samme tabel

  4. ASP.NET/Identity Error:Enhedstypen ApplicationUser er ikke en del af modellen for den aktuelle kontekst