PostgreSQL修改被檢視引用的表的欄位
阿新 • • 發佈:2020-01-21
在pg中,當我們需要修改表的某個欄位時,如果該欄位剛好被檢視引用,必須先將引用的物件刪除,才能修改對應的欄位。
例如:
bill=# create table test_t (id int,info text,crt_time timestamp,c1 varchar(10)); CREATE TABLE bill=# create index idx_test_t on test_t(c1); CREATE INDEX bill=# create view v_test_t as select id,c1 from test_t; CREATE VIEW bill=# alter table test_t alter column c1 type varchar(32); psql: ERROR: cannot alter type of a column used by a view or rule DETAIL: rule _RETURN on view v_test_t depends on column "c1"
不過這個情況在oracle中並不存在:
SQL> create table test_t (id int,info varchar2(100),c1 varchar(10)); Table created. SQL> create index idx_test_t on test_t(c1); Index created. SQL> create view v_test_t as select id,c1 from test_t; View created. SQL> alter table test_t modify(c1 varchar(32)); Table altered.
那麼我們在pg中該如何去修改被檢視引用的表的欄位呢?
pg中支援將DDL語句封裝在事務中處理,所以從刪除依賴,到修改欄位,再到重建依賴,都可以封裝在一個事務中完成。
例子:
不過這種方法需要注意:
- DDL是需要對錶加排它鎖的,排它鎖與所有其他鎖衝突,因此建議在事務開始時設定鎖超時引數,避免問題。
- 如果修改欄位涉及到rewrite table(例如int改到text),那麼表很大時間會很久。如果需要很久,意味著需要長時間持有排它鎖(堵塞也是比較嚴重的)。
begin; -- 開始事務 set local lock_timeout = '1s'; -- 設定鎖超時 drop view v_test_t; -- 刪除依賴檢視 alter table test_t alter column c1 type varchar(32); -- 修改欄位長度 create view v_test_t as select id,c1 from test_t; -- 建立檢視 end; -- 結束事務
除此之外我們還可以通過修改pg中元資料表的方式去實現。
因為pg的定義都記錄在元資料中,所以某些操作,可以直接修改元資料來實現。比如從numeric低精度修改到高精度,從字串短長度修改到長長度。
但是不建議這麼做,直接修改元資料存在隱患,甚至可能對資料庫造成不可修復的傷害。
例子:
1、首先檢視將要修改的C1欄位的pg_attribute元資訊
bill=# select attrelid::regclass,* from pg_attribute where attname='c1';
attrelid | attrelid | attname | atttypid | attstattarget | attlen | attnum | attndims | attcacheoff | atttypmod | attbyval | attstorage | attalign | attnotnull | atthasdef | atthasmissing | attiden
tity | attgenerated | attisdropped | attislocal | attinhcount | attcollation | attacl | attoptions | attfdwoptions | attmissingval
------------+----------+---------+----------+---------------+--------+--------+----------+-------------+-----------+----------+------------+----------+------------+-----------+---------------+--------
-----+--------------+--------------+------------+-------------+--------------+--------+------------+---------------+---------------
test_t | 200125 | c1 | 1043 | -1 | -1 | 4 | 0 | -1 | 36 | f | x | i | f | f | f |
| | f | t | 0 | 100 | | | |
idx_test_t | 200136 | c1 | 1043 | -1 | -1 | 1 | 0 | -1 | 36 | f | x | i | f | f | f |
| | f | t | 0 | 100 | | | |
v_test_t | 200137 | c1 | 1043 | -1 | -1 | 2 | 0 | -1 | 36 | f | x | i | f | f | f |
| | f | t | 0 | 100 | | | |
(3 rows)
在修改時,需要將這三個atttypmod一起修改掉。
變長欄位的長度為4位元組頭+實際長度,所以36表示可以儲存32個字元。
2、修改為varchar(64)這樣操作
bill=# update pg_attribute set atttypmod=68 where attname='c1' and attrelid in (200125,200136,200137);
UPDATE 3
3、檢視更新後的結構
bill=# \d+ test_t
Table "public.test_t"
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
----------+-----------------------------+-----------+----------+---------+----------+--------------+-------------
id | integer | | | | plain | |
info | text | | | | extended | |
crt_time | timestamp without time zone | | | | plain | |
c1 | character varying(64) | | | | extended | |
Indexes:
"idx_test_t" btree (c1)
Access method: heap
bill=# \d+ v_test_t
View "public.v_test_t"
Column | Type | Collation | Nullable | Default | Storage | Description
--------+-----------------------+-----------+----------+---------+----------+-------------
id | integer | | | | plain |
c1 | character varying(64) | | | | extended |
View definition:
SELECT test_t.id,test_t.c1
FROM test_t;
bill=# \d+ idx_test_t
Index "public.idx_test_t"
Column | Type | Key? | Definition | Storage | Stats target
--------+-----------------------+------+------------+----------+--------------
c1 | character varying(64) | yes | c1 | extended |
btree,for table "public.test_t"