Преобразование столбцов таблицы в пары ключ-значение - PullRequest
4 голосов
/ 13 апреля 2010

Я пишу процедуру PL / SQL, которая загружает некоторые данные из схемы A в схему B. Обе схемы очень разные, и я не могу изменить структуру схемы B.

Столбцы в различных таблицах схемы A (объединенные в виде) необходимо вставить в схему B в виде пар ключ => значение в 2 столбцах таблицы, каждая в отдельной строке. Например, имя сотрудника может присутствовать как employee.firstname в схеме A, но его необходимо ввести в схеме B как:

id=>1, key=>'A123', value=>'Smith'

Существует почти 100 ключей, которые могут быть добавлены в будущем. Это означает, что я не хочу жестко кодировать ни одну из этих клавиш.

Пример кода:

create table schema_a_employees (
    emp_id number(8,0),
    firstname varchar2(50),
    surname varchar2(50)
);
insert into schema_a_employees values ( 1, 'James', 'Smith' );
insert into schema_a_employees values ( 2, 'Fred', 'Jones' );

create table schema_b_values (
    emp_id number(8,0),
    the_key varchar2(5),
    the_value varchar2(200)
);

Я думал, что элегантное решение, скорее всего, будет включать в себя таблицу поиска для определения того, какое значение вставлять для каждого ключа, и не требует эффективного жесткого кодирования десятков похожих операторов, таких как ....

insert into schema_b_values ( 1, 'A123', v_firstname );
insert into schema_b_values ( 1, 'B123', v_surname );

Что я хотел бы иметь, так это иметь локальную справочную таблицу в схеме A, в которой перечислены все ключи из схемы B, а также столбец, который дает имя столбца в таблице в схеме A, который должен использоваться для заполнения, например ключ "A123" в схеме B должен быть заполнен значением столбца "имя" в схеме A, например,

create table schema_a_lookup (
    the_key varchar2(5),
    the_local_field_name varchar2(50)
);
insert into schema_a_lookup values ( 'A123', 'firstname' );
insert into schema_a_lookup values ( 'B123', 'surname' );

Но я не уверен, как я мог бы динамически использовать значения из таблицы поиска, чтобы сообщить Oracle, какие столбцы использовать.

Итак, мой вопрос: существует ли элегантное решение для заполнения таблицы schema_b_values ​​данными из schema_a_employees без жесткого кодирования для каждого возможного ключа (т. Е. A123, B123 и т. Д.)?

Приветствие.

Ответы [ 2 ]

1 голос
/ 13 апреля 2010

Мне нравится INSERT ALL в качестве подхода, потому что он предлагает инкапсулированную транзакцию: либо все строки вставлены, либо нет. Мой опыт миграции данных заключается в том, что это, как правило, весьма итеративный процесс, поэтому все, что помогает в очистке и регрессии, является явным благом.

SQL> declare
  2      l_src_name varchar2(30) := 'SCHEMA_A_EMPLOYEES';
  3      l_tgt_name varchar2(30) := 'SCHEMA_B_VALUES';
  4      stmt varchar2(32767);
  5  begin
  6      for pk_rec in ( select cc.table_name, cc.column_name
  7                        from user_cons_columns cc
  8                             , user_constraints c
  9                        where c.table_name = l_src_name
 10                        and c.constraint_type = 'P'
 11                        and cc.table_name = l_src_name )
 12      loop
 13          stmt := 'insert all';
 14          for col_rec in ( select * from schema_a_lookup )
 15          loop
 16              stmt := stmt||' into '||l_tgt_name||' values ('
 17                   ||pk_rec.column_name
 18                   ||', '''||col_rec.the_key||''','
 19                   ||col_rec.the_local_field_name
 20                   ||')';
 21          end loop;
 22          stmt := stmt||' select * from '||l_src_name;
 23      end loop;
 24      execute immediate stmt;
 25  end;
 26  /

PL/SQL procedure successfully completed.

SQL> 

Сколько строк?

SQL> select * from schema_b_values;

    EMP_ID THE_K THE_VALUE
---------- ----- ---------------
         1 A123  James
         2 A123  Fred
         1 B123  Smith
         2 B123  Jones

SQL>

Я завернул запросы в PL / SQL, потому что это указывает на дальнейшую автоматизацию. Вы можете добавить таблицу для хранения имен таблиц SOURCE и TARGET. Очевидно, есть возможность повеселиться, если исходная таблица имеет составной первичный ключ.

1 голос
/ 13 апреля 2010

Я искренне надеюсь, что ваша Схема B не является страшной парой ключ-значение . Хотя некоторые динамические таблицы значений атрибутов могут быть полезны в некоторых ситуациях, вы обнаружите, что все, кроме самых простых запросов, почти невозможно написать в дизайне EAV (даже простой запрос типа «найти всех сотрудников с именем Джон Смит» трудно написать - и невозможно настроить).

В любом случае, в вашем случае вы хотите написать динамический запрос, который будет выглядеть так:

SQL> INSERT ALL
  2     INTO schema_b_values VALUES (emp_id, 'A123', firstname)
  3     INTO schema_b_values VALUES (emp_id, 'B123', surname)
  4     SELECT emp_id, firstname, surname
  5       FROM schema_a_employees;

4 rows inserted

Вы можете использовать следующий запрос для генерации оператора:

SQL> SELECT 'INSERT ALL ' sql_lines FROM dual
  2  UNION ALL
  3  SELECT 'INTO schema_b_values VALUES (emp_id, '''
  4            || dbms_assert.simple_sql_name(the_key)
  5            || ''', '
  6            || dbms_assert.simple_sql_name(the_local_field_name)
  7            ||')'
  8    FROM schema_a_lookup
  9  UNION ALL
 10  SELECT 'SELECT * FROM schema_a_employees' FROM dual;

SQL_LINES
--------------------------------------------------------------------------------
INSERT ALL
INTO schema_b_values VALUES (emp_id, 'A123', firstname)
INTO schema_b_values VALUES (emp_id, 'B123', surname)
SELECT * FROM schema_a_employees

Затем вы можете использовать EXECUTE IMMEDIATE или DBMS_SQL для выполнения этого оператора.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...