【问题标题】:Is there something like a "column symlink" in Oracle?Oracle中有类似“列符号链接”的东西吗?
【发布时间】:2011-08-14 13:36:47
【问题描述】:

我想暂时通过两个列名访问我的数据库中的一列。

为什么?列名选错了,我想重构它。因为我希望我的 webapp 在更改列名时保持稳定,所以最好

  1. 有一个(我们称之为)符号链接,名为 better_column_name 指向列 bad_column_name
  2. 将 Web 应用程序更改为使用 better_column_name
  3. 删除符号链接并将列重命名为 better_column_name

“重构数据库”建议实际添加第二列,该列在提交时同步以实现此目的。我只是希望 Oracle 有一种更简单的方法,工作量更少,开销也更少。

【问题讨论】:

  • 为什么不将应用程序代码的发布与您想要的数据库更改一起协调呢?在开发/UAT 环境中测试更改,并以受控、协调的方式促进生产。这个问题说实话有点吓人
  • 为什么可怕? Web 应用程序分布在多个 Web 服务器上,将其推广到所有服务器需要一些时间(即几分钟)。当然,我可以宣布一个小的维护窗口,以便一步推出 DB 和 Web 应用程序更改。但如果可以避免的话,我宁愿不这样做。

标签: database oracle refactoring-databases


【解决方案1】:

您可以为表格创建视图。并移植您的应用程序以使用该视图而不是表格。

create table t (bad_name varchar2(10), c2 varchar2(10));
create view vt as select bad_name AS good_name, c2 from t;

insert into vt (good_name, c2) values ('blub', 'blob');

select * from t;
select * from vt;

【讨论】:

  • 那个drop table语句会让他失去所有的数据:-)
  • 你是对的 :),我已经编辑了我的答案并删除了 drop 语句。
【解决方案2】:

此问题的最佳解决方案仅在 Oracle 11g 第 2 版:基于版本的重新定义中可用。这个非常酷的特性允许我们使用特殊的触发器和视图来维护不同版本的数据库表和 PL/SQL 代码。 Find out more.

本质上这是 Oracle 对@AHorseWithNoName's suggestion 的内置实现。

【讨论】:

    【解决方案3】:

    重命名表格:

    alter table mytable rename to mytable_old;
    

    使用原始表名创建一个视图,其中包含 bad_column_name 和 better_column_name指向同一列(当然还有所有其他列):

    create or replace view mytable as
      select column1
      , column2
      , ...
      , bad_column_name
      , bad_column_name better_column_name
      from mytable_old
    ;
    

    由于这个视图默认是可更新的(我在这里假设 mytable 有一个主键),你可以从视图中插入/更新/删除,使用 bad_column_name 或 better_column_name 都没关系。

    重构后,删除视图并重命名表和列:

    drop view mytable;
    alter table mytable_old rename column bad_column_name to better_column_name;
    alter table mytable_old rename to mytable;
    

    【讨论】:

      【解决方案4】:

      只要您的代码同时使用这两个列名,我就没有办法解决您将在该表中拥有两个(真实)列这一事实。

      我将添加具有正确名称的新列,然后创建一个触发器来检查哪一列已被修改并相应地更新“其他”列。因此,无论正在更新什么,该值都会与另一列同步。

      在迁移所有使用旧列的代码后,移除触发器并删除旧列。

      编辑

      触发器会这样做:

      CREATE OR REPLACE TRIGGER ...
          ...
          UPDATE OF bad_column_name, better_column_name ON the_table 
          ...
      BEGIN
        IF UPDATING ('BAD_COLUMN_NAME') THEN 
           :new.better_column_name = :new.bad_column_name
        END IF;
      
        IF UPDATING ('BETTER_COLUMN_NAME') THEN 
           :new.bad_column_name = :new.better_column_name
        END IF;
      END;
      

      IF 语句的顺序控制在有人同时更新两列的情况下哪个更改具有“更高优先级”。

      【讨论】:

        【解决方案5】:

        如果您使用的是 11g,则可以考虑使用虚拟列。我可能会想稍微改变一下顺序;重命名真实列并使用旧(坏)名称创建虚拟列,然后可以随意删除。当然,您可能会受到限制,并且可能会影响其他对象无效,从而使该订单不太适合您。

        【讨论】:

        • 虚拟列是执行此操作的一种方式,但它并非无痛。将 VC 用作旧的坏列的问题在于,它将破坏插入/更新该列的所有内容(因为 DML 无法分配给虚拟列)。相反,使用 VC 作为新名称意味着必须立即推出所有必须更新它的代码,同时将 VC 列切换为真正的列。嗯....
        • 对,没想到这方面。很公平。
        • 但是使用 VC 作为 better_column_name 而不是 old_bad_column_name 也有优点。这意味着应用程序代码可以转换到新的列名,同时保持旧引用不变。
        • @kevinmcdonnell - 但正如 APC 指出的那样,只有查询中的旧引用,而不是 DML;无论是旧的还是新的,您都不能拥有试图插入 VC 的代码。所以你不能有一些设置better_column_name的代码和其他设置bad_column_name的代码。因此,这个答案被否决了;我把它留在这里,以防其他人有同样的错误想法......
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-10
        • 1970-01-01
        • 2021-08-04
        • 2012-05-31
        • 2012-11-27
        • 2017-11-21
        相关资源
        最近更新 更多