在MySQL數據庫里,在添加字段時可以添加到表的任意位置, 那么在POSTGRESQL里我們是否可以實現呢?
答案是肯定可以的。
PG的語法里並沒有類似AFTER, BEFORE的子句。
總結:
第一種方法失敗,甚至能導致數據庫自動重啟。
第二種方法可行,但如果數據量較大,業務停止的時間就會加長。
哪果數據量較小,可以考慮第二種方法。但如果數據量大,停機就沒有辦法接受了, 可以讓業務修改代碼來完成需求了。
嘗試方法一:
修改pg_attribute中的表字段位置:
postgres=# create table t_col(id int4, name varchar(9));
CREATE TABLE ^
postgres=# insert into t_col values(1,'a');
INSERT 0 1
postgres=# insert into t_col values(2,'b');
INSERT 0 1
postgres=# select attrelid,attname,attnum from pg_attribute where attrelid = (select relfilenode from pg_class where relname = 't_col');
attrelid | attname | attnum
----------+----------+--------
353681 | tableoid | -7
353681 | cmax | -6
353681 | xmax | -5
353681 | cmin | -4
353681 | xmin | -3
353681 | ctid | -1
353681 | id | 1
353681 | name | 2
(8 rows)
postgres=# select ctid, * from t_col;
ctid | id | name
-------+----+------
(0,1) | 1 | a
(0,2) | 2 | b
(2 rows)
postgres=# update pg_attribute set attnum=3 where attrelid=353681 and attname='id';
UPDATE 1
postgres=# update pg_attribute set attnum=1 where attrelid=353681 and attname='name';
UPDATE 1
postgres=# update pg_attribute set attnum=2 where attrelid=353681 and attname='id';
UPDATE 1
postgres=# select attrelid,attname,attnum from pg_attribute where attrelid = (select relfilenode from pg_class where relname = 't_col');
attrelid | attname | attnum
----------+----------+--------
353681 | tableoid | -7
353681 | cmax | -6
353681 | xmax | -5
353681 | cmin | -4
353681 | xmin | -3
353681 | ctid | -1
353681 | name | 1
353681 | id | 2
(8 rows)
postgres=# \d t_col
Table "public.t_col"
Column | Type | Modifiers
--------+----------------------+-----------
name | character varying(9) |
id | integer
從上面的結果來看,字段順序已經被調整了過來,嘗試讀取數據:
postgres=# select * from t_col; 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. !>
異常了,數據庫被強制重啟。
2017-12-05 15:35:11.451 CST [24682-13] [postgres@127.0.0.1]@postgres LOG: statement: select * from t_col; 2017-12-05 15:35:11.569 CST [5935-18] LOG: server process (PID 24682) was terminated by signal 11: Segmentation fault 2017-12-05 15:35:11.569 CST [5935-19] DETAIL: Failed process was running: select * from t_col; 2017-12-05 15:35:11.569 CST [5935-20] LOG: terminating any other active server processes 2017-12-05 15:35:11.570 CST [23383-2] WARNING: terminating connection because of crash of another server process 2017-12-05 15:35:11.570 CST [23383-3] DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory. 2017-12-05 15:35:11.570 CST [23383-4] HINT: In a moment you should be able to reconnect to the database and repeat your command. 2017-12-05 15:35:11.570 CST [25249-1] [postgres@127.0.0.1]@postgres FATAL: the database system is in recovery mode 2017-12-05 15:35:11.574 CST [5935-21] LOG: archiver process (PID 23384) exited with exit code 1 2017-12-05 15:35:11.574 CST [23422-1] [repluser@192.168.252.3]@[unknown] WARNING: terminating connection because of crash of another server process 2017-12-05 15:35:11.574 CST [23422-2] [repluser@192.168.252.3]@[unknown] DETAIL: The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory. 2017-12-05 15:35:11.574 CST [23422-3] [repluser@192.168.252.3]@[unknown] HINT: In a moment you should be able to reconnect to the database and repeat your command. 2017-12-05 15:35:11.575 CST [5935-22] LOG: all server processes terminated; reinitializing 2017-12-05 15:35:11.657 CST [25250-1] LOG: database system was interrupted; last known up at 2017-12-05 15:33:17 CST 2017-12-05 15:35:12.373 CST [25250-2] LOG: database system was not properly shut down; automatic recovery in progress 2017-12-05 15:35:12.376 CST [25250-3] LOG: redo starts at 89/FF0DBF80 2017-12-05 15:35:12.376 CST [25250-4] LOG: record with zero length at 89/FF0DC070 2017-12-05 15:35:12.376 CST [25250-5] LOG: redo done at 89/FF0DC038 2017-12-05 15:35:12.395 CST [25250-6] LOG: MultiXact member wraparound protections are now enabled 2017-12-05 15:35:12.397 CST [5935-23] LOG: database system is ready to accept connections 2017-12-05 15:35:12.397 CST [25254-1] LOG: autovacuum launcher started
其實t_col這張表已經損壞了,當對這張表操作時,都會出現重啟的現象。
嘗試把表字段調回去:
postgres=# update pg_attribute set attnum=3 where attrelid=353681 and attname='name';
UPDATE 1
postgres=# update pg_attribute set attnum=1 where attrelid=353681 and attname='id';
UPDATE 1
postgres=# update pg_attribute set attnum=2 where attrelid=353681 and attname='name';
UPDATE 1
postgres=# \d t_col;
Table "public.t_col"
Column | Type | Modifiers
--------+----------------------+-----------
id | integer |
name | character varying(9) |
操作測試:
postgres=# insert into t_col values(3,'c'); INSERT 0 1 postgres=# select * from t_col; id | name ----+------ 1 | a 2 | b 3 | c (3 rows)
嘗試方法二:
1. 禁止表寫入數據。
postgres=# begin work; BEGIN postgres=# lock table t_col in share mode; LOCK TABLE
2. 在另一個會話中創建要求字段順序的表,並將原表數據插入到新表中:
postgres=# create table t_col_new(name varchar(9), id int4); CREATE TABLE postgres=# insert into t_col_new select name, id from t_col; INSERT 0 3 postgres=# select * from t_col_new; name | id ------+---- a | 1 b | 2 c | 3 (3 rows)
3. 對表進行RENAME操作:
postgres=# alter table t_col rename to t_col_old; ALTER TABLE postgres=# alter table t_col_new rename to t_col; ALTER TABLE postgres=# commit work; COMMIT
4. 數據效驗:
postgres=# select * from t_col; name | id ------+---- a | 1 b | 2 c | 3 (3 rows)
