是否可以在Postgres 8.1中更改列的自然顺序?
我知道不应该依赖列的顺序 - 这并不是我的关键 - 我只需要它以一种更令人愉悦的方式生成一些自动生成的内容,以便字段顺序从pgadmin一直匹配到后端再到前端。
是否可以在Postgres 8.1中更改列的自然顺序?
我知道不应该依赖列的顺序 - 这并不是我的关键 - 我只需要它以一种更令人愉悦的方式生成一些自动生成的内容,以便字段顺序从pgadmin一直匹配到后端再到前端。
如果你的数据库不太大并且可以承受一些停机时间,那么你可以:
pg_dump --create --column-inserts databasename > databasename.pgdump.sql
CREATE TABLE
语句split
命令拆分文件,编辑后使用 cat
合并回来drop database databasename
psql --single-transaction -f databasename.pgdump.sql
--single-transaction
会非常慢如果使用所谓的大型对象,请确保它们包含在转储文件中。我不确定它们是否默认包含在 8.1 版本中。
请注意,由于此操作涉及到数据库系统表的操作,请谨慎进行,仅在必要情况下执行。
截至 postgres 8.3 版本,此方法可行。但对于更早版本,请自行斟酌。
ALTER TABLE... RENAME COLUMN...
,因为它可以可靠地实现相同的结果。 - Daniel Vérité我在2007年在pgsql-admin中询问了这个问题。 Tom Lane本人宣称在目录中更改顺序实际上是不可行的。
澄清一下:这适用于使用当前工具的用户。这并不意味着无法实现。在我看来,应该这样做。
对于Postgres 12仍然是正确的。
我也希望如此。是的,对于我的应用场景而言,订单并不重要,但这确实让我感到不适。
我的解决办法如下:
此方法将确保您保留任何现有数据,
当前表格顺序:
id, name, email
1. 使用我想要的顺序创建一个新版本的表格,使用临时名称。
在这个例子中,我想让email
出现在name
之前。
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;
警告:该方法会删除表属性,例如唯一索引和其他在drop 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 │
└─────┴────────────┴───────┘
如果您要重新排序的表格具有数百列,您将希望自动获取给定列的顺序,这样您就可以复制、微调,然后粘贴到上面的视图中。
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=# 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=#
test=# CREATE TABLE mangle_me (a integer, b text);
CREATE TABLE
test=# INSERT INTO mangle_me VALUES (1, 'a text');
INSERT 0 1
test=# SELECT attrelid, attname, attnum FROM pg_attribute WHERE attrelid = 'mangle_me'::regclass;
attrelid │ attname │ attnum
══════════╪══════════╪════════
27035 │ tableoid │ -6
27035 │ cmax │ -5
27035 │ xmax │ -4
27035 │ cmin │ -3
27035 │ xmin │ -2
27035 │ ctid │ -1
27035 │ a │ 1
27035 │ b │ 2
(8 rows)
test=# UPDATE pg_attribute SET attnum = 4 WHERE attrelid = 27035 AND attname = 'a';
UPDATE 1
test=# UPDATE pg_attribute SET attnum = 1 WHERE attrelid = 27035 AND attname = 'b';
UPDATE 1
test=# UPDATE pg_attribute SET attnum = 2 WHERE attrelid = 27035 AND attname = 'a';
UPDATE 1
test=# TABLE mangle_me;
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.
The connection to the server was lost. Attempting reset: Failed.
!?>
在表上创建一个具有不同列顺序的视图。
您可以像使用表一样使用该视图;它将接受INSERT
、UPDATE
和DELETE
操作。
如果您坚持要改变列的顺序,并且不想有长时间的停机时间,唯一的方法是创建一个逻辑备用数据库,其中列的顺序已经改变。一旦逻辑复制追赶上来,您可以将应用程序切换到逻辑备用数据库,并删除原始数据库。
这带来了逻辑复制的所有困难:
DDL不会被复制
在繁忙的数据库上,逻辑复制可能太慢,永远无法追赶上