在Oracle中重新排序表的列
Posted
技术标签:
【中文标题】在Oracle中重新排序表的列【英文标题】:Re-order columns of table in Oracle 【发布时间】:2011-06-23 19:24:16 【问题描述】:我有一个包含 50 多列的表,我需要交换前两列的顺序。使用 Oracle 完成此任务的最佳方法是什么?假设表名是 ORDERDETAILS,前两列是 ITEM_ID 和 ORDER_ID。重命名完成后,表名仍应为 ORDERDETAILS,但前两列将为 ORDER_ID 和 ITEM_ID。 FWIW、列类型和其余列及其顺序无关紧要。
如果我错了,请纠正我,但我认为一般步骤是:
-
重命名现有表。
删除主键约束。
使用正确的列顺序重新创建表。
列表项
运行 INSERT INTO .. SELECT 以将数据从 temp 移动到第 3 步中的表中。
删除临时表。
我对 Oracle 的经验很少,所以我可能缺少一两步。
主键是否意味着 Oracle 中的索引?删除主键是否也会删除索引?
非常感谢 SQL 示例。
编辑:感谢那些质疑为什么需要完成而不是提供帮助的人。回答您关于为什么需要完成的问题:我正在遵循其他人的命令,他们说我需要这样做,并且列的顺序很重要。我对此的想法/意见无关紧要。
【问题讨论】:
我更像是一个 MS SQL 人,但我想不出你需要放弃 PK 的任何理由。您的步骤不包括创建临时表,除非您指的是重命名的原始表。 2 - 删除所有约束,然后 3a 将约束添加到 temp_table。为新表添加统计信息集合。备份也。也不知道你在用索引做什么。 不确定我能想到任何需要这个的理由,但如果它只是为了索引(?)的目的,你可以只在 order_id、item_id 而不是 item_id、order_id 上创建索引。猛烈抨击您需要重新定义表格的动机。 对于那些询问它为什么有用的人:我有一个应用程序可以将一些元数据列添加到现有表中。如果将这些列放在前面,这对所有相关人员都很有用,以便在查看表时我们添加的列在 sqldeveloper 中立即可见。 如果列顺序相同,在两个表之间复制时,您可以只使用 SELECT * 而不是命名每个该死的列。 【参考方案1】:自 Oracle 12c 发布以来,现在可以更轻松地在逻辑上重新排列列。
Oracle 12c 增加了对使列不可见的支持,并且该功能可用于在逻辑上重新排列列。
引用自documentation on invisible columns:
当您使不可见的列可见时,该列将作为最后一列包含在表格的列顺序中。
示例
创建表:
CREATE TABLE t (
a INT,
b INT,
d INT,
e INT
);
添加一列:
ALTER TABLE t ADD (c INT);
将列移到中间:
ALTER TABLE t MODIFY (d INVISIBLE, e INVISIBLE);
ALTER TABLE t MODIFY (d VISIBLE, e VISIBLE);
DESCRIBE t;
Name
----
A
B
C
D
E
学分
我是从 an article by Tom Kyte on new features in Oracle 12c 那里了解到的。
【讨论】:
谢谢,这正是我所需要的!完美运行。 @Jonas,那么我们还需要在查询中更改顺序吗? @UnKnown,新顺序也将由为 INSERT 指定的值使用(如果未指定列名)。 这是一个使用不可见列的例程,允许您以任何所需的顺序对列重新排序。 connor-mcdonald.com/2013/07/22/12c-invisible-columns 来自同一篇文章的注释.....“使用不可见列的一个积极的副作用是能够对表中的列进行逻辑重新排序。我强调这将是合乎逻辑的,而不是物理,列的重新排序。”和“(请注意,在磁盘上,列实际上将存储为 A、B、D、E 和 C。)”【参考方案2】:查看包 DBMS_Redefinition。它将使用新的顺序重建表。可以通过在线表格完成。
正如 Phil Brown 所说,在执行此操作之前请仔细考虑。但是,在行中扫描列并在更新时移动数据会产生开销。我使用的列排序规则(无特定顺序):
将相关的列组合在一起。 可空列之前的非空列。 经常搜索的未索引列优先。 很少填充可空列最后。 首先是静态列。 稍后可更新 varchar 列。 在其他可搜索列之后的索引列。这些规则相互冲突,并且尚未在最新版本中对所有的性能进行测试。大多数已经在实践中进行了测试,但我没有记录结果。放置选项针对三个相互冲突的目标之一:易于理解的列放置;快速数据检索;并且更新时的数据移动最少。
【讨论】:
请记住...即使 DBMS_REDEFINITION 只是在幕后创建一个具有新列顺序的新表,将所有数据从旧表移动到新表,删除旧表,并重命名新表。 老话题,但我不认为有必要“首先经常搜索未索引的列”。或“其他可搜索列之后的索引列。” (实际上非常相似)自 Oracle 9i 或更早版本以来,定位最右边的列需要大量 CPU 开销。那时我当然需要这样做,但从那以后就不需要了。 @DavidAldridge Oracle 在提高表扫描速度方面付出了很多努力,并且可能已经显着降低了扫描最右边列的成本,我预计跳过列仍然会产生成本。一个明确的答案需要我没有资源的测试。 @BillThor “轶事不是数据”,但我在多年前建立了一个高度非规范化的数据集市,大约有 250 列——大部分是数字,一些 varchar2 分散在其中——这是我测量回来的然后在读取最右边的列时非常重要,无论是用于搜索还是仅读取全表扫描。在某些主要版本或其他版本中突然修复之前,绝对值得经历物理重新排序表的痛苦。我认为是 9i 或 10g。可能会找到关于它的 asktom 评论..【参考方案3】:我遵循了 Jonas 的上述解决方案,它运行良好,直到我需要添加第二列。我发现,当使列再次可见时,Oracle 不一定按语句中列出的顺序将它们设置为可见。
为了证明这一点,请遵循上面 Jonas 的示例。正如他所展示的,一旦这些步骤完成,表格就会按照您期望的顺序排列。当您添加另一列时,事情就会崩溃,如下所示:
示例(续乔纳斯):
在 C 列之前添加另一列。
ALTER TABLE t ADD (b2 INT);
使用上面演示的技术将新添加的 B2 列移动到 C 列之前。
ALTER TABLE t MODIFY (c INVISIBLE, d INVISIBLE, e INVISIBLE);
ALTER TABLE t MODIFY (c VISIBLE, d VISIBLE, e VISIBLE);
DESCRIBE t;
Name
----
A
B
B2
D
E
C
如上图C列已经移到了末尾。似乎上面的 ALTER TABLE 语句以 D、E、C 的顺序处理列,而不是语句中指定的顺序(可能是物理表顺序)。为确保将列放置在所需的位置,有必要以所需的顺序一一显示列。
ALTER TABLE t MODIFY (c INVISIBLE, d INVISIBLE, e INVISIBLE);
ALTER TABLE t MODIFY c VISIBLE;
ALTER TABLE t MODIFY d VISIBLE;
ALTER TABLE t MODIFY e VISIBLE;
DESCRIBE t;
Name
----
A
B
B2
C
D
E
【讨论】:
【参考方案4】:很遗憾,Oracle 不允许这样做,开发人员一直要求我这样做..
这是一个有点危险,有点快速和肮脏的方法:
-
确保您有足够的空间来复制表格
注意任何约束、授权、索引、同义词、触发器,嗯.. 可能是其他一些我没有考虑过的东西 - 属于表 - ?
CREATE TABLE table_right_columns AS SELECT column1 column3, column2 FROM table_wrong_columns; -- Notice how we correct the position of the columns :)
DROP TABLE table_wrong_columns;
'ALTER TABLE table_right_columns 重命名为 table_wrong_columns;`
现在是令人讨厌的部分:重新创建您在上面第 2 步中记下的所有项目
检查哪些代码现在无效,然后重新编译以检查错误
并且下次创建表时,请考虑未来的要求! ;)
【讨论】:
如何保存字段cmets:***.com/questions/6910255/…【参考方案5】:使用视图来改变列的位置: 创建视图 CORRECTED_POSITION 作为 选择 co1_1、col_3、col_2 FROM UNORDERDED_POSITION 应该有帮助。
发出此请求是为了在使用 SELECT * FROM [table_name] 的地方生成一些报告。或者,某些企业采用分层方法来放置信息,以便从后端获得更好的可读性。
谢谢 迪利普
【讨论】:
以上是关于在Oracle中重新排序表的列的主要内容,如果未能解决你的问题,请参考以下文章