如何更改PostgreSQL数据库表中列的位置?


Answers:


106

PostgreSQL Wiki中的“ 更改列位置 ”说:

PostgreSQL当前基于表的attnum列定义列顺序pg_attribute。更改列顺序的唯一方法是重新创建表,或者添加列并旋转数据,直到达到所需的布局为止。

这是相当薄弱的,但是在标准SQL中,在他们的辩护中,也没有解决方法来重新定位列。支持更改列的顺序位置的数据库品牌正在定义SQL语法的扩展。

我想到了另一个想法:您可以定义a VIEW,以指定您喜欢的列顺序,而无需更改列在基表中的物理位置。


3
@Dana:我认为这就是Wiki文章中“重新创建表”的含义。
Bill Karwin

2
“转储数据库” ::破坏数据的好方法。因此“擦洗海量数据库”效果。
肯特·弗雷德里克

31
@Kent:令人怀疑的是,postgres开发人员在确保数据一致性方面还有很长的路要走,这肯定适用于pg_dump。毕竟,如果还原失败,那么执行数据库备份有什么意义呢?
丹娜桑那

@Dana,是的,但是您要添加1)一个大的转储进程,然后您删除它,然后又要消耗大量时间。如果您有一个非常庞大的数据库(通常只有37列),那么磁盘IO阻塞会带来风险。
肯特·弗雷德里克

@DanatheSane这些是超级古老的注释,但是Bill所说的基本上是同一回事,而不是进行完整的数据库转储,您只需转储表(和依赖项),杀死原始表,然后重新创建。无需使整个数据库脱机,也无需花费时间重新创建不受影响的内容。另一方面,如果有很多依赖性,我发现进行完全转储(如您建议的那样)要容易得多。
vol7ron 2012年

36

在PostgreSQL中,添加字段时会在表末尾添加字段。如果我们需要插入特定位置,则

alter table tablename rename to oldtable;
create table tablename (column defs go here);
insert into tablename (col1, col2, col3) select col1, col2, col3 from oldtable;

3
哇,这太好了,我相信这应该是公认的答案!
Tommaso Thea Cioni,

是的,真的很有帮助,非常感谢!
Acuna

您还可以像这样将当前表复制到新的旧表中:CREATE TABLE oldtable AS SELECT * FROM tablename;
瑞安

29

这篇文章很旧,可能已经解决了,但我遇到了同样的问题。我通过创建指定新列顺序的原始表的视图来解决它。

从这里,我可以使用视图或从视图创建新表。

    创建视图original_tab_vw AS
    选择a.col1,a.col3,a.col4,a.col2
    从original_tab
    a.col1不为空的地方-或其他任何地方
    SELECT * INTO new_table FROM original_tab_vw

重命名或删除原始表,然后将新表的名称设置为旧表。


2
这似乎是一个非常合理的解决方案。太糟糕了,没有任何GUI工具可以自动执行此过程。
Quolonel问题

4
一个好的解决方案,但只复制数据类型(不复制主键等)
Regisz 2014年

1
或者-只需按原样使用带有重新排序的列的视图即可。性能应降到最低。
pscl

1
这是最好的解决方案。
Nikolay Shindarov

23

尽管在必须绝对更改列顺序且使用外键时重新排列列的方法很笨拙,但它还是要先转储整个数据库的数据,然后再转储模式(pg_dump -s databasename > databasename_schema.sql)。接下来,编辑架构文件以根据需要重新排列列,然后从架构中重新创建数据库,最后将数据还原到新创建的数据库中。


1
为什么要投票?正如公认的答案所指出的那样,引用PostgreSQL Wiki:»更改列顺序的唯一方法是重新创建表,或添加列并旋转数据,直到达到所需的布局。» 此解决方案不是最佳解决方案(这些答案都不是没有内置操作来完成任务的),但是它确实提供了一种重新排列表格中各列的方法。
Ville

1
我再说一遍,没有很好的方法可以做到这一点,而我上面概述的一种在必须绝对重新排列列的情况下重新排列列的有效方法。如果您对我的回答不满意,请评论一下为什么您认为这是不可接受的解决方案。
Ville

3
实际上,当表是另一个表中的外键时,这是一个很好的解决方案。所有其他解决方案在此方案中均不起作用。最后,使用pg_dump --column-inserts -s databasename> databasename_schema.sql
Alejandro Salamanca Mazuelo


5

在PGAdmin中打开表,然后在底部的SQL窗格中复制SQL Create Table语句。然后打开查询工具并粘贴。如果表中有数据,请将表名更改为“ new_name”,否则,在“删除表”行中删除注释“-”。根据需要编辑列顺序。请注意最后一列中丢失/多余的逗号(如果已移动)。执行新的“ SQL创建表”命令。刷新并...瞧瞧。

对于设计阶段的空表,此方法非常实用。

如果表中有数据,我们还需要重新排列数据的列顺序。这很容易:使用以下INSERT命令将旧表导入到新表中:

INSERT INTO new ( c2, c3, c1 ) SELECT * from old;

...其中c2c3c1是列c1c2c3旧表在其新职位。请注意,在这种情况下,必须为已编辑的“旧”表使用“新”名称,否则将丢失数据。如果列名很多,很长和/或很复杂,则使用与上述相同的方法将新表结构复制到文本编辑器中,并在将新表列表复制到INSERT语句之前在其中创建新列列表。

在检查DROP完一切之后,使用旧表并将“ new”名称更改为“ old” ALTER TABLE new RENAME TO old;,即可完成操作。


1

我当时正在对许多表进行重新排序,并且不想一遍又一遍地编写相同的查询,因此我编写了一个脚本来为我完成所有这些工作。本质上,它:

  1. 从获取表创建SQL pg_dump
  2. 从转储中获取所有可用的列
  3. 将列按所需顺序排列
  4. 修改原始pg_dump查询以创建具有数据的重新排序的表
  5. 掉旧表
  6. 重命名新表以匹配旧表

可以通过运行以下简单命令来使用它:

./reorder.py -n schema -d database table \
    first_col second_col ... penultimate_col ultimate_col --migrate

它会打印出sql,以便您可以验证和测试它,这是我基于sql的一个重要原因pg_dump。您可以在这里找到github仓库


0

我使用Django,如果您不想头痛,它需要每个表中的id列。不幸的是,我很粗心,我的表bp.geo_location_vague没有包含该字段。我开始了一点小技巧。第1步:

CREATE VIEW bp.geo_location_vague_vw AS
    SELECT 
        a.id, -- I change order of id column here. 
        a.in_date,
        etc
    FROM bp.geo_location_vague a

第2步:(不创建表-表将自动创建!)

SELECT * into bp.geo_location_vague_cp2 FROM bp.geo_location_vague_vw

第三步:

CREATE SEQUENCE bp.tbl_tbl_id_seq;
ALTER TABLE bp.geo_location_vague_cp2 ALTER COLUMN id SET DEFAULT nextval('tbl_tbl_id_seq');
ALTER SEQUENCE bp.tbl_tbl_id_seq OWNED BY bp.geo_location_vague_cp2.id;
SELECT setval('tbl_tbl_id_seq', COALESCE(max(id), 0)) FROM bp.geo_location_vague_cp2;

因为我需要在表中使用bigserial伪类型。将SELECT *插入pg后,将创建bigint类型的insetad bigserial。

步骤4:现在我们可以删除视图,删除源表并以旧名称重命名新表。俩成功结束了。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.