Сравните две схемы и обновите старую схему новыми столбцами новой схемы. - PullRequest
3 голосов
/ 25 февраля 2010

У меня есть база данных Oracle с двумя схемами. Один старый, а другой новый. Я хотел бы обновить старую схему новыми столбцами новой схемы.

Я получаю таблицы с изменениями по следующему запросу.

select distinct table_name
from
(
    select table_name,column_name
    from all_tab_cols
    where owner = 'SCHEMA_1'

    minus

    select table_name,column_name
    from all_tab_cols
    where owner = 'SCHEMA_2'
)

С помощью этого запроса я получаю таблицы. Как я могу обновить старые таблицы схем новыми столбцами? Мне не нужны данные, только столбцы.

Ответы [ 3 ]

5 голосов
/ 25 февраля 2010

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

Если вы все еще хотите сделать это самостоятельно, лучший способ, который я нашел, состоит в том, чтобы извлечь определения схемы в текст, а затем выполнить сравнение текста. Пока все отсортировано по алфавиту, вы можете использовать функцию сравнения документов в Microsoft Word (или FC.EXE, DIFF или эквивалентную), чтобы выделить различия.

Следующий скрипт SQLPlus выводит определение схемы в алфавитном порядке, чтобы разрешить сравнение. Есть два раздела. В первом разделе перечислены все столбцы в формате:

table_name.column_name: data_type = data_default <nullable>

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

PK constraint_name on table_name (pk_column_list)
FK constraint_name on table_name (fk_column_list)
CHECK constraint_name on table_name (constraint_definition)

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

set serveroutput on;
set serveroutput on size 1000000;
declare
  rowcnt    pls_integer := 0;
  cursor c_column is
     select table_name, column_name, data_type, 
        data_precision, data_length, data_scale, 
        data_default, nullable,
        decode(data_scale, null, null, ',') scale_comma,
        decode(default_length, null, null, '= ') default_equals
      from all_tab_columns where owner = 'BCC'
      order by table_name, column_name;
  cursor c_constraint is
      select c.table_name, c.constraint_name,
         decode(c.constraint_type,
                'P','PK',
                'R','FK',
                'C','CHECK',
                 c.constraint_type) constraint_type,
         c.search_condition, 
         cc.column_1||cc.comma_2||cc.column_2||cc.comma_3||cc.column_3||cc.comma_4||cc.column_4||
         cc.comma_5||cc.column_5||cc.comma_6||cc.column_6||cc.comma_7||cc.column_7 r_columns   
       from all_constraints c,
          ( select owner, table_name, constraint_name, nvl(max(position),0) max_position,
             max( decode( position, 1, column_name, null ) ) column_1,
             max( decode( position, 2, decode(column_name, null, null, ',' ), null ) ) comma_2,
             max( decode( position, 2, column_name, null ) ) column_2,
             max( decode( position, 3, decode(column_name, null, null, ',' ), null ) ) comma_3,
             max( decode( position, 3, column_name, null ) ) column_3,
             max( decode( position, 4, decode(column_name, null, null, ',' ), null ) ) comma_4,
             max( decode( position, 4, column_name, null ) ) column_4,
             max( decode( position, 5, decode(column_name, null, null, ',' ), null ) ) comma_5,
             max( decode( position, 5, column_name, null ) ) column_5,
             max( decode( position, 6, decode(column_name, null, null, ',' ), null ) ) comma_6,
             max( decode( position, 6, column_name, null ) ) column_6,
             max( decode( position, 7, decode(column_name, null, null, ',' ), null ) ) comma_7,
             max( decode( position, 7, column_name, null ) ) column_7
           from all_cons_columns
           group by owner, table_name, constraint_name ) cc
       where c.owner = 'BCC'
       and c.generated != 'GENERATED NAME'
       and cc.owner = c.owner
       and cc.table_name = c.table_name
       and cc.constraint_name = c.constraint_name
       order by c.table_name, 
          decode(c.constraint_type,
                 'P','PK',
                 'R','FK',
                 'C','CHECK',
                 c.constraint_type) desc, 
          c.constraint_name;
begin
  for c_columnRow in c_column loop
    dbms_output.put_line(substr(c_columnRow.table_name||'.'||c_columnRow.column_name||': '||
                         c_columnRow.data_type||'('||
                         nvl(c_columnRow.data_precision, c_columnRow.data_length)||
                         c_columnRow.scale_comma||c_columnRow.data_scale||') '||
                         c_columnRow.default_equals||c_columnRow.data_default||
                         ' <'||c_columnRow.nullable||'>',1,255));
    rowcnt := rowcnt + 1;
  end loop;
  for c_constraintRow in c_constraint loop
    dbms_output.put_line(substr(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
                         c_constraintRow.table_name||' ('||
                         c_constraintRow.search_condition||
                         c_constraintRow.r_columns||') ',1,255));
    if length(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
                         c_constraintRow.table_name||' ('||
                         c_constraintRow.search_condition||
                         c_constraintRow.r_columns||') ') > 255 then
       dbms_output.put_line('... '||substr(c_constraintRow.constraint_type||' '||c_constraintRow.constraint_name||' on '||
                            c_constraintRow.table_name||' ('||
                            c_constraintRow.search_condition||
                            c_constraintRow.r_columns||') ',256,251));
    end if;
    rowcnt := rowcnt + 1;
  end loop;
end;
/

К сожалению, есть несколько ограничений:

  1. Встроенные возвраты каретки и пробелы в data_defaults, а также проверки определений ограничений могут быть выделены как различия, даже если они не влияют на схему.
  2. Не включает альтернативные ключи, уникальные индексы или индексы производительности. Для этого потребуется третий оператор SELECT в сценарии, ссылающийся на представления каталога all_ind_columns и all_indexes.
  3. Не включает сведения о безопасности, синонимы, пакеты, триггеры и т. Д. Пакеты и триггеры лучше всего сравнивать, используя подход, аналогичный тому, который вы первоначально предложили. Другие аспекты определения схемы могут быть добавлены к приведенному выше сценарию.
  4. Приведенные выше определения FK идентифицируют ссылающиеся столбцы внешнего ключа, но не PK или таблицу, на которую ссылаются. Еще одна деталь, которую я так и не нашел.

Даже если вы не используете сценарий. Есть определенное техническое удовольствие от игры с этим материалом. ; -)

Мэтью

3 голосов
/ 25 февраля 2010

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

Вам следует воспользоваться инструментом сравнения схем.

Доступны бесплатные версии - посмотрите на этот вопрос по поводу ошибки сервера:

https://serverfault.com/questions/26360/how-can-i-diff-two-oracle-10g-schemas

Я бы предложил загрузить Oracle SQL Developer и использовать встроенный инструмент сравнения схем (хотя для этого требуется лицензия Change Management Pack).

3 голосов
/ 25 февраля 2010

Боюсь, что сейчас я не могу сделать больше для вас, но это должно дать вам основную идею.

Выбирает операторы столбцов ADD и DROP, которые можно выполнить после тщательного их просмотра .

Не справляется

  • созданные / удаленные таблицы
  • тип данных / точность изменения существующих столбцов (ALTER TABLE MODIFY)
  • DEFAULT VALUES (поэтому вы не можете применить его к таблице с данными, когда новый столбец равен NOT NULL)
  • Проверка ограничений, ограничения внешнего ключа

Я попробовал это с некоторыми основными типами данных (NUMBER, VARCHAR2, DATE), и это сработало. Удачи:)


SELECT    'ALTER TABLE ' || LOWER(table_name)
       || ' ADD ' || LOWER(column_name) || ' ' || data_type
       || CASE WHEN data_type NOT IN ('DATE') THEN '(' || data_length || ')' END
       || CASE WHEN nullable='Y' THEN ' NOT NULL' END
       || ';' cmd
  FROM all_tab_cols c2
 WHERE owner = 'SCHEMA_1'
   AND NOT EXISTS ( SELECT 1
                      FROM all_tab_cols c1
                     WHERE owner = 'SCHEMA_2'
                       AND c1.table_name = c2.table_name
                       AND c1.column_name = c2.column_name )
UNION ALL
SELECT    'ALTER TABLE ' || LOWER(table_name)
       || ' DROP COLUMN ' || LOWER(column_name) || ';'
  FROM all_tab_cols c2
 WHERE owner = 'SCHEMA_2'
   AND NOT EXISTS ( SELECT 1
                      FROM all_tab_cols c1
                     WHERE owner = 'SCHEMA_1'
                       AND c1.table_name = c2.table_name
                       AND c1.column_name = c2.column_name )
ORDER BY cmd;
...