1. 程式人生 > 資料庫 >PostgreSQL修改被檢視引用的表的欄位

PostgreSQL修改被檢視引用的表的欄位

在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語句封裝在事務中處理,所以從刪除依賴,到修改欄位,再到重建依賴,都可以封裝在一個事務中完成。

例子:
不過這種方法需要注意:

  1. DDL是需要對錶加排它鎖的,排它鎖與所有其他鎖衝突,因此建議在事務開始時設定鎖超時引數,避免問題。
  2. 如果修改欄位涉及到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"