English 中文(简体)
有可能改变Postgres中列的自然顺序吗?
原标题:
  • 时间:2008-09-24 10:39:12
  •  标签:

有可能改变Postgres 8.1中列的自然顺序吗?

我知道你不应该依赖列顺序-这对我所做的事情来说并不是必不可少的-我只需要它来让一些自动生成的东西以一种更令人愉快的方式出现,这样字段顺序就可以从pgadmin到后端再到前端一直匹配。

最佳回答

实际上,您可以直接更改列顺序,但我几乎不建议这样做,如果您决定这样做,您应该非常小心。

如。

# 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)

同样,因为这是在玩弄数据库系统表,所以如果您觉得确实需要这样做,请格外小心。

这是从后期版本8.3开始工作的,对于之前的版本,您的相似性可能会有所不同。

问题回答

如果您的数据库不是很大,并且您可以承受一些停机时间,那么您可以:

  1. Disable write access to the database
    this is essential as otherwise any changes after starting the next point will be lost
  2. pg_dump --create --column-inserts databasename > databasename.pgdump.sql
  3. Edit apropriate CREATE TABLE statement in databasename.pgdump.sql
    If the file is too big for your editor just split it using split command, edit, then assemble back using cat
  4. drop database databasename
    You do have a recent backup, just in case, do you?
  5. psql --single-transaction -f databasename.pgdump.sql
    If you don t use --single-transaction it will be very slow

如果使用所谓的大型对象,请确保它们包含在转储中。我不确定它们在8.1中是否默认。

我在2007年的pgsql管理中问过这个问题。汤姆·莱恩本人宣称,改变目录中的顺序实际上是不可行的。

Clarification: this applies for users with the present tools. Does not mean, it could not be implemented. IMO, it should be.
Still true for Postgres 12.

我也想要同样的。是的,订单对我的用例来说并不重要,但它只是让我感到不舒服:)

我正在做的解决办法如下。

此方法将确保您保留任何现有数据,

  1. Create a new version of the table using the ordering I want, using a temporary name.
  2. Insert all data into that new table from the existing one.
  3. Drop the old table.
  4. Rename the new table to the "proper name" from "temporary name".
  5. Re-add any indexes you previously had.
  6. Reset ID sequence for primary key increments.

当前表格顺序:

id, name, email

1.使用我想要的排序,使用临时名称创建一个新版本的表

在本例中,我希望电子邮件位于名称之前。

CREATE TABLE mytable_tmp
(
  id SERIAL PRIMARY KEY,
  email text,
  name text
);

2.将现有表中的所有数据插入到新表中

INSERT INTO mytable_tmp   --- << new tmp table
(
  id
, email
, name
)
SELECT
  id
, email
, name
FROM mytable;  --- << this is the existing table

3.放下旧表

DROP TABLE mytable;

4.将新表从“临时名称”重命名为“适当名称”

ALTER TABLE mytable_tmp RENAME TO mytable;

5.重新添加您以前拥有的任何索引

CREATE INDEX ...

6.重置主键增量的ID序列

SELECT setval( public.mytable_id_seq , max(id)) FROM mytable;

Reorder the columns in postgresql walkthrough

警告:此方法删除表财产,如唯一索引和其他意外结果,这些都是由于执行删除your_table而导致的。因此,您需要在之后重新添加这些内容。

--create a table where column bar comes before column baz:
CREATE TABLE foo ( moo integer, bar character varying(10), baz date ); 

--insert some data
insert into foo (moo, bar, baz) values (34,  yadz , now()); 
insert into foo (moo, bar, baz) values (12,  blerp , now()); 
select * from foo; 
    ┌─────┬───────┬────────────┐ 
    │ moo │  bar  │    baz     │ 
    ├─────┼───────┼────────────┤ 
    │  34 │ yadz  │ 2021-04-07 │ 
    │  12 │ blerp │ 2021-04-07 │ 
    └─────┴───────┴────────────┘ 

-- Define your reordered columns here, don t forget one, 
-- or it ll be missing from the replacement.
drop view if exists my_view;
create view my_view as ( select moo, baz, bar from foo );
select * from my_view; 

DROP TABLE IF EXISTS foo2; 
--foo2 is your replacement table that has columns ordered correctly
create table foo2 as select * from my_view; 
select * from foo2;
--finally drop the view and the original table and rename
DROP VIEW my_view; 
DROP TABLE foo; 
ALTER TABLE foo2 RENAME TO foo; 

--observe the reordered columns:
select * from foo;
    ┌─────┬────────────┬───────┐ 
    │ moo │    baz     │  bar  │ 
    ├─────┼────────────┼───────┤ 
    │  34 │ 2021-04-07 │ yadz  │ 
    │  12 │ 2021-04-07 │ blerp │ 
    └─────┴────────────┴───────┘ 

Get the prior order of column names for copying and pasting

如果要重新排序的表有数百列,则需要自动获取给定的列顺序,以便可以复制、轻推,然后粘贴到上述视图中。

SELECT string_agg(column_name,  , ) from ( 
    select * FROM INFORMATION_SCHEMA.COLUMNS  
    WHERE table_name =  your_big_table   
    order by ordinal_position asc 
) f1;

打印内容:

column_name_1,column_name_2, ..., column_name_n

复制上面命名的顺序,将它们移动到它们所属的位置,然后粘贴到顶部的视图中。

您可以通过创建一个新表并按您希望的顺序选择旧表中的列来获得所需的列顺序:

CREATE TABLE test_new AS SELECT b, c, a FROM test;
SELECT * from test_new;
 b | c | a 
---+---+---
 2 | 3 | 1
(1 row)

请注意,这只复制数据,不复制修饰符、约束、索引等。。

一旦按照您想要的方式修改了新表,请删除原始表并更改新表的名称:

BEGIN;
DROP TABLE test;
ALTER TABLE test_new RENAME TO test;
COMMIT;

不幸的是,不是。列顺序完全取决于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=#




相关问题