Oracle
 sql >> база данни >  >> RDS >> Oracle

Извличане на редове от DB, включително зависими редове

Може да има някакъв инструмент, който вече го прави, но произволното извличане на всички таблици с редове от начална таблица само по себе си е малка задача за разработка. Не мога да напиша всичко вместо вас, но мога да ви накарам да започнете - започнах да го пиша, но след около 20 минути разбрах, че е малко повече работа, която искам да ангажирам с неплатен отговор.

Виждам, че се прави най-добре чрез рекурсивна PL/SQL процедура, която би използвала dbms_ouput и user_cons_columns &user_constraints за създаване на израз за вмъквания за таблицата източник. Можете да мамите малко, като напишете всички вмъквания, сякаш колоните са char стойности, тъй като Oracle имплицитно ще преобразува всички char стойности в правилния тип данни, ако приемем, че вашите NLS параметри са идентични в изходната и целевата система.

Забележете, че пакетът по-долу ще има проблеми, ако имате кръгови връзки във вашите таблици; освен това при по-ранни версии на Oracle може да ви свърши буферното пространство с dbms_output. И двата проблема могат да бъдат решени чрез вмъкване на генерирания sql в етапна таблица, която има уникален индекс на sql, и прекратяване на рекурсията, ако получите уникален ключов сблъсък. Голямото спестяване на време по-долу е функцията MakeParamList, която преобразува курсор, който връща списък от колони, или в списък, разделен със запетая, или в един израз, който ще покаже стойностите на тези колони в кавички, разделена със запетая форма, когато се изпълнява като изберете клауза в заявка срещу таблицата.

Обърнете внимание също, че следният пакет наистина няма да работи, докато не го модифицирате допълнително (една от причините, поради които спрях да го пиша):Генерираният първоначален израз за вмъкване се основава на предположението, че предаденият аргумент constraint_vals ще доведе до единичен ред генериран - разбира се, това почти сигурно не е така, след като започнете да рекурсирате (тъй като ще имате много дъщерни редове за родител). Ще трябва да промените генерирането на първия оператор (и последващите рекурсивни извиквания), за да бъде вътре в цикъл, за да се справите със случаите, когато извикването на първото извикване EXECUTE IMMEDIATE генерира множество редове вместо един. Основите, за да го накарате да работи, са тук, просто трябва да изпипате детайлите и да накарате външния курсор да работи.

Една последна бележка също:Малко вероятно е да изпълните тази процедура, за да генерирате набор от редове, които, когато бъдат вмъкнати в целева система, биха довели до "чист" набор от данни, тъй като въпреки че ще получите всички зависими данни, това данните може да зависят от други таблици, които не сте импортирали (напр. първата дъщерна таблица, която срещате, може да има други външни ключове, които сочат към таблици, несвързани с вашата първоначална таблица). В такъв случай може да искате да започнете с подробните таблици и да продължите нагоре, вместо надолу; правейки това, вие също бихте искали да обърнете реда на изразите, които сте генерирали, или с помощта на помощна програма за скриптове, или чрез вмъкване на sql в етапна таблица, както споменах по-горе, с последователност, след което я избирате с сортиране в низходящ ред .

Що се отнася до извикването му, предавате разделения със запетая списък с колони за ограничаване като constraint_cols и съответния разделен със запетая списък със стойности като constraint_vals, напр.:

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

Ето го:

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. Как да конвертирам стойности, разделени със запетая, в редове в Oracle?

  2. Може ли Oracle да изпълнява функции на командния ред на Windows?

  3. Мога ли да деактивирам тригер вътре в тригер в oracle?

  4. ora:00936 Грешка при липсващ израз

  5. ExecuteNonQuery винаги връща нула. Мога ли да използвам тази стойност 0 в моя код за валидиране?