【问题标题】:Compare two schemas and update the old schema with the new columns of new schema比较两个模式并用新模式的新列更新旧模式
【发布时间】:2013-05-08 21:05:35
【问题描述】:

我有一个具有两个模式的 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'
)

通过这个查询,我得到了表格。如何使用新列更新旧模式表?我不需要数据,只需要列。

【问题讨论】:

  • 小心,您的查询将返回SCHEMA_1 中的新列,但您不会得到SCHEMA_2 中存在但SCHEMA_1 中不存在的列。而且您找不到已更改的列。祝你好运:)
  • 谢谢彼得朗.. 我知道我不是甲骨文专家 :) 如果有人有一些想法如何做到这一点。请与我分享....
  • 您的新架构是否包含数据?删除并重新创建表是一种选择吗?你有几张桌子?您是只更改了列,还是还有新表?
  • ya...两种模式都包含数据。我们可以做到不掉线吗?新架构中大约有 80 个表。新架构中有 3 个新表和许多带有新列的表。
  • 市场上有很多解决方案(例如 Toad、RedGate)可以为您做到这一点?它们是一种选择,还是您需要零成本的解决方案?

标签: oracle compare schema


【解决方案1】:

架构比较工具是个好主意。数据库架构比大多数人认为的要复杂得多,两个数据库架构之间的每一个差异都有可能导致错误。

如果您仍然热衷于自己动手,我发现的最佳方法是将架构定义提取到文本中,然后运行文本比较。只要所有内容都按字母顺序排序,您就可以使用 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 模式详细信息的有用参考。当您在客户站点并且没有可用的常用工具时,或者当安全​​策略阻止您直接从您自己的 PC 访问客户站点数据库时,这可能是一个很好的知识。

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 或被引用的表。还有一个我一直没时间做的细节。

即使您不使用脚本。玩这些东西会给技术人员带来一定的乐趣。 ;-)

马修

【讨论】:

  • Matthew,我不是 Oracle 专家,所以你能解释一下你的代码输出在哪里吗?我运行成功了但是不知道结果在哪里。
【解决方案2】:

恐怕我现在不能为你做更多的事情,但这应该会给你一个基本的想法。

它选择ADDDROP 列语句,您可以仔细查看它们后执行它们。

不处理

  • 创建/删除表
  • 现有列的数据类型/精度更改 (ALTER TABLE MODIFY)
  • DEFAULT VALUES(因此当新列为NOT NULL 时,您无法将其应用于包含数据的表)
  • 检查约束、外键约束

我尝试了一些基本的数据类型(NUMBERVARCHAR2DATE),它成功了。祝你好运:)


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;

【讨论】:

    【解决方案3】:

    我开始为此写一个答案,但我的注意事项列表比答案长,所以我决定放弃它。

    您应该使用架构比较工具。

    有可用的免费版本 - 看看 Server Fault 上的这个问题:

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

    我的建议是下载 Oracle 的 SQL Developer 并使用内置的模式差异工具(尽管这需要您拥有变更管理包许可证)。

    【讨论】:

    • 是的 :) 我最初的回答有点说教。 “您应该在版本控制脚本中进行所有架构更改,并且......等等等等”。退格退格。 :)
    • 小心这个建议:SQL Developer schmea diff 工具不是免费的。它需要变更管理包的许可证,这是企业版许可证的额外费用。
    • @Nick Pierpoint - 也许您应该再次拖出肥皂盒,因为所有架构更改都应该在源代码管理中。
    • @APC 关于变更管理包许可证的好点 - 我以前没见过这个。似乎是一个奇怪的限制。我想“差异”正在使用包中的内置包。所以是的......拿出肥皂盒。
    猜你喜欢
    • 2011-07-22
    • 2012-09-11
    • 1970-01-01
    • 2018-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多