【问题标题】:How do I alter the position of a column in a PostgreSQL database table?如何更改 PostgreSQL 数据库表中列的位置?
【发布时间】:2010-09-22 02:14:06
【问题描述】:

我尝试了以下方法,但没有成功:

ALTER TABLE person ALTER COLUMN dob POSITION 37;

【问题讨论】:

标签: sql database postgresql alter-table


【解决方案1】:

Alter column position”在 PostgreSQL Wiki 中说:

PostgreSQL 当前定义了列 基于attnum 列的顺序 pg_attribute 表。唯一的办法 更改列顺序是通过 重新创建表,或通过添加 列和旋转数据,直到你 达到所需的布局。

这很弱,但在他们的防御中,在标准 SQL 中,也没有重新定位列的解决方案。支持更改列序号位置的数据库品牌正在定义 SQL 语法的扩展。

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

【讨论】:

  • 'dump the database' :: 破坏数据的好方法。从而产生“清理海量数据库”的效果。
  • @Kent:值得怀疑的是,postgres 开发人员在确保数据一致性方面做了很多工作,这肯定适用于 pg_dump。毕竟,如果还原失败,进行数据库备份有什么意义?
  • @Dana,是的,但是您正在添加 1) 一个要转储的大进程,然后您删除,然后您将有大量耗时的负载。如果您有一个 非常 庞大的数据库(通常是 37 列),那么您将面临磁盘 IO 阻塞的风险。
  • @DanatheSane 这些是超级老 cmets,但比尔所说的本质上是一样的,而不是进行完整的数据库转储,您只需转储表(和依赖项),杀掉原来的,然后重新创建。无需使整个数据库脱机,或花时间重新创建不受影响的东西。另一方面,如果有很多依赖项,我发现做一个完整的转储(如你所建议的)要容易得多。
  • 这就是您可能需要列顺序的原因 - postgresql.org/docs/current/interactive/sql-copy.html - 如果指定了列列表,则 COPY 只会将指定列中的数据复制到文件或从文件中复制。如果表中有任何列不在列列表中,COPY FROM 将为这些列插入默认值。
【解决方案2】:

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

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

【讨论】:

  • 哇,这太棒了,我相信这应该是公认的答案!
  • 您也可以像这样将当前表复制到新的旧表中:CREATE TABLE oldtable AS SELECT * FROM tablename;
  • 这里是一个真实世界值的例子:insert into newTable (id, created, start, end, message) SELECT id, created, start, end, message FROM oldTable;
  • 从一个表移动到另一个表并不容易,因为还有其他与它们相关的对象,例如我们的约束。
  • 我认为这个解决方案也会弄乱外键。 ALTER TABLE ... RENAME TO ... 似乎相应地改变了其他表中现有的外键关系。这意味着最终外键指向oldtable,但数据在新表中。我假设需要手动迁移所有外键关系,然后才能正确删除 oldtable
【解决方案3】:

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

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

创建视图 original_tab_vw AS 选择 a.col1、a.col3、a.col4、a.col2 FROM original_tab 一个 WHERE a.col1 IS NOT NULL -- 或其他 从 original_tab_vw 中选择 * INTO new_table

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

【讨论】:

  • 这似乎是一个非常合理的解决方案。太糟糕了,没有任何 GUI 工具可以自动执行此过程。
  • 很好的解决方案但是只复制了数据类型(没有主键等)
  • 或者 - 只需按原样使用带有重新排序列的视图。性能下降应该最小。
  • 这是最好的解决方案。
【解决方案4】:

当必须绝对更改列顺序并且使用外键时,重新排列列的一个笨拙选项是首先转储整个数据库的数据,然后仅转储架构 (pg_dump -s databasename > databasename_schema.sql)。接下来编辑架构文件以根据需要重新排列列,然后从架构重新创建数据库,最后将数据恢复到新创建的数据库中。

【讨论】:

  • 为什么要投反对票?正如公认的答案指出的那样,引用 PostgreSQL Wiki:»更改列顺序的唯一方法是重新创建表,或者添加列并旋转数据,直到达到所需的布局。»这个解决方案不是最优的(这些答案都不是在没有内置操作来完成任务的情况下),但它确实提供了一种重新排列表格中的列的方法。
  • 我再说一遍,没有好的方法可以做到这一点,而我上面概述的 一种有效的方法来重新排列列,如果它们绝对必须重新排列的话。如果您对我的回答投反对票,请评论为什么您认为这是一个不可接受的解决方案。
  • 其实这个表在其他表是外键的情况下是一个很好的解决方案。在这种情况下,所有其他解决方案都不起作用。最后,使用 pg_dump --column-inserts -s databasename > databasename_schema.sql
【解决方案5】:

我认为您目前不能:请参阅this article on the Postgresql wiki

本文中的三个解决方法是:

  1. 重新创建表
  2. 添加列和移动数据
  3. 用视图隐藏差异。

【讨论】:

    【解决方案6】:

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

    对于设计阶段的空表,这个方法还是比较实用的。

    如果表格有数据,我们也需要重新排列数据的列顺序。这很简单:使用INSERT 将旧表导入到新版本中:

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

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

    检查一切正常后,DROP 旧表并使用ALTER TABLE new RENAME TO old; 将“新”名称更改为“旧”,然后您就完成了。

    【讨论】:

    • 很确定这个过程也需要重新创建所有 FK 约束。
    【解决方案7】:

    我正在对很多表进行重新排序,并且不想一遍又一遍地编写相同的查询,所以我编写了一个脚本来为我完成这一切。本质上,它:

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

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

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

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

    【讨论】:

      【解决方案8】:

      我使用 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
      

      第 3 步:

      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 * into pg 后会创建 bigint 类型的 insetad bigserial。

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

      【讨论】:

        【解决方案9】:

        有一些解决方法可以做到这一点:

        1. 重新创建整个表

        2. 在当前表中创建新列

        3. 创建视图

        https://tableplus.com/blog/2018/09/postgresql-is-it-possible-to-alter-column-order-position-in-a-table.html

        【讨论】:

          猜你喜欢
          • 2011-11-02
          • 2015-02-27
          • 1970-01-01
          • 2015-12-06
          • 2012-04-15
          • 2015-08-15
          • 2021-08-03
          • 1970-01-01
          • 2021-08-24
          相关资源
          最近更新 更多