是否可以在Postgres中更改列的自然顺序?
时间:2020-03-06 14:39:14 来源:igfitidea点击:
是否可以在Postgres 8.1中更改列的自然顺序?
我知道我们不应该依赖列顺序,这对我在做什么并不重要,我只需要它可以使一些自动生成的内容以更令人愉悦的方式出现,从而使字段顺序从pgadmin从后端到前端。
解决方案
不幸的是,不是,不是。列顺序完全取决于Postgres。
在查询中指定列顺序是唯一可靠(合理)的方法。就是说,我们通常可以通过更改表来获得不同的顺序,如下例所示,因为通常(不保证返回)列的添加顺序是将它们添加到表的顺序。
postgres=# create table a(a int, b int, c int); CREATE TABLE postgres=# insert into a values (1,2,3); INSERT 0 1 postgres=# select * from a; a | b | c ---+---+--- 1 | 2 | 3 (1 row) postgres=# alter table a add column a2 int; ALTER TABLE postgres=# select * from a; a | b | c | a2 ---+---+---+---- 1 | 2 | 3 | (1 row) postgres=# update a set a2 = a; UPDATE 1 postgres=# alter table a drop column a; ALTER TABLE postgres=# alter table a rename column a2 to a; ALTER TABLE postgres=# select * from a; b | c | a ---+---+--- 2 | 3 | 1 (1 row) postgres=#
正如其他答案所述,我们不能更改列的顺序,这取决于postgres。我们可以(并且应该!)使用视图解决问题。就报告查询而言,它看起来就像一个表。就像是:
create view my_view as select * from my_table order by some_col;
如果数据库不是很大,并且我们可以承受一些停机时间,则可以:
- 禁用对数据库的写访问,这是必不可少的,否则开始下一个点之后的所有更改都将丢失
- pg_dump --create --column-inserts数据库名> databasename.pgdump.sql
- 在databasename.pgdump.sql中编辑适当的
CREATE TABLE
语句如果文件对于编辑器来说太大,只需使用split
命令将其拆分,进行编辑,然后使用cat
进行组合 drop database databasename
我们确实有最近的备份,以防万一,是吗?- psql --single-transaction -f databasename.pgdump.sql如果不使用--single-transaction将会非常慢
如果使用所谓的大对象,请确保它们包含在转储中。我不确定它们是否默认为8.1.
实际上,我们可以直接改变列的顺序,但是我几乎不建议这样做,如果我们决定这样做,则应该非常小心。
例如。
# CREATE TABLE test (a int, b int, c int); # INSERT INTO test VALUES (1,2,3); # SELECT * FROM test; a | b | c ---+---+--- 1 | 2 | 3 (1 row)
现在需要技巧的是,我们需要使用postgres用户连接到数据库,以便可以修改系统表。
# SELECT relname, relfilenode FROM pg_class WHERE relname='test'; relname | relfilenode ---------+------------- test_t | 27666 (1 row) # SELECT attrelid, attname, attnum FROM pg_attribute WHERE attrelid=27666; attrelid | attname | attnum ----------+----------+-------- 27666 | tableoid | -7 27666 | cmax | -6 27666 | xmax | -5 27666 | cmin | -4 27666 | xmin | -3 27666 | ctid | -1 27666 | b | 1 27666 | a | 2 27666 | c | 3 (9 rows)
attnum是唯一的列,因此在按如下方式修改列号时需要使用一个临时值:
# UPDATE pg_attribute SET attnum=4 WHERE attname='a' AND attrelid=27666; UPDATE 1 # UPDATE pg_attribute SET attnum=1 WHERE attname='b' AND attrelid=27666; UPDATE 1 # UPDATE pg_attribute SET attnum=2 WHERE attname='a' AND attrelid=27666; UPDATE 1 # SELECT * FROM test; b | a | c ---+---+--- 1 | 2 | 3 (1 row)
同样,由于这是数据库系统表的问题,如果我们确实需要执行此操作,请格外小心。
从postgres 8.3开始,此功能已开始运行,并且在以前的版本中,里程可能会有所不同。