GaussDB(DWS)アプリケーションの戦闘:ビューが参照するテーブルに対するDDL操作

要約: GaussDB(DWS)はPostgresから発展しました。Postgresと同様に、テーブルがビューによって参照される場合、一部のDDL操作は特定のシナリオで直接実行できません。

背景ノート

GaussDB(DWS)はPostgresから発展しました。Postgresと同様に、テーブルがビューによって参照される場合、ビューによって参照されるフィールドのタイプの変更、テーブルの削除などの特定のシナリオでは、一部のDDL操作を直接実行できません。新しく追加されたフィールドは操作可能です主な理由は、ビューがテーブルのフィールドを参照しており、ビューが変更された場合は変更する必要があるためです。以下のコンテンツのこの部分を簡単にデモンストレーションしてみましょう。ビューが参照するテーブルがDDL操作を実行するとどうなりますか。次に、テーブルのフィールドなどを変更する方法を確認します。

実験コンテンツを生成する

2つのテストテーブルと3つのテストビューを作成します。作成されるSQLステートメントは次のとおりです。すべてのビューがt1のフィールドを使用し、t2のフィールドを使用しないことに注意してください。

CREATE TABLE t1 (id int,name varchar(20));
CREATE TABLE t2 (id int,name varchar(20));
CREATE OR REPLACE VIEW v1 as select * from t1;
CREATE OR REPLACE VIEW v2 as select a.* from t1 a inner join t2 b on a.id = b.id;
CREATE OR REPLACE VIEW v3 as select a.* from v1 a inner join v2 b on a.id = b.id inner join t1 c on a.id = c.id;

1つは、テーブルを削除します

DROP TABLE t1;
DROP TABLE t2;

実行結果プロンプトから判断すると、ビューの依存関係のため、DROP TABLEは正常に実行されませんでした。DROP ... CASCADEを使用して従属ビューを一緒に削除できますが、通常はビューを削除したくありません。

2、フィールドを変更する

ALTER TABLE T1 MODIFY NAME VARCHAR(30);
ALTER TABLE T2 MODIFY NAME VARCHAR(30);

実行結果のプロンプトから判断すると、ビューv2がこのフィールドを使用したため、t1テーブルはフィールドタイプを変更できませんでした。また、ビューがt2フィールドを使用していないためt2テーブルは正常に変更されました。t2テーブルはビューで使用されていましたが、関連付けの場合、ビューのフィールドはt2テーブルのフィールドを使用しないため、t2テーブルのフィールドタイプを正常に変更できます。

後続の実験で目標を正常に達成するには、ここでv2のビューを変更してt2のフィールドを取得します

ALTER TABLE T2 MODIFY NAME VARCHAR(20);
CREATE OR REPLACE VIEW v2 as select b.* from t1 a inner join t2 b on a.id = b.id;

三、新しい分野

ALTER TABLE t1 ADD COMMENT VARCHAR(30);
ALTER TABLE t2 ADD  COMMENT VARCHAR(30);

ビューの作成時に、まだ存在しないフィールドを参照する方法がないため、フィールドの追加に制限はありません。ビューの定義を確認しますCREATE VIEW v1 AS SELECT * FROM t1;現在、v1の新しいフィールド情報はありますか?答えは「いいえ」です。新しいフィールドを追加するには、ビューを更新する必要があります

select * from v2;
CREATE OR REPLACE VIEW v2 as select a.* from t1 a inner join t2 b on a.id = b.id;
select * from v2;

ビューが参照するテーブル定義を変更するにはどうすればよいですか?

問題は、上記の変更されたフィールドと同様に、ビューによって参照されるテーブルの定義をどのように変更できるかということです。

次のステップに分けられると思います

ビュー定義をテキストにバックアップ->テーブル定義をテキストにバックアップ->テーブル定義をテキストで変更->バックアップテーブル(ALTER TABLE XX RENAME TO XX_BAK)->変更されたテーブルを追加->データを挿入->バックアップビューテキストリフレッシュビュー

取得するのが難しいのは、どのビューがテーブルによって参照されているかです。参照関係を取得するにはpg_rewriteを使用する必要があり、循環的に取得するには再帰的な..を使用する必要があります。

1つは、ビュー定義をテキストにバックアップする

最初にテーブルデザインのビューを取得します。このSQLは少し複雑です。以下に説明するいくつかの手順があります

pg_rewriteを使用してテーブルとビュー間の依存関係を取得する

select c.nspname as schemaname,b.relname,rel_oid,b.relkind,d.oid as ori_oid,d.relname ori_name
    from (
    select unnest(regexp_matches(ev_action::text,':relid (\d+)', 'g'))::oid  rel_oid,ev_class --rel_oid 被依赖对象 ,ev_class 视图名称
    from pg_rewrite 
    union 
    select unnest(regexp_matches(ev_action::text,':resorigtbl (\d+)','g'))::oid,ev_class
    from pg_rewrite 
     ) deptbl                   --pg_write获取依赖关系
    inner join pg_class b       --被依赖对象获取表名等信息
    on deptbl.rel_oid = b.oid
    inner join pg_namespace c
    on b.relnamespace = c.oid
    inner join pg_class d     --视图获取视图名等信息,且用于排除pg_write获取的自身对象,即rel_oid <> ev_class
    on deptbl.ev_class = d.oid
    and deptbl.rel_oid <> d.oid
    where  b.relname = 't2'; --指定表名t2

再帰的xx as loopステートメントを使用して、関連するすべてのビューを取得します

with recursive rec_view as (
    select c.nspname as schemaname,b.relname,rel_oid,b.relkind,d.oid as ori_oid,d.relname ori_name
    ,0 as level  --level防止死循环
    from (
    select unnest(regexp_matches(ev_action::text,':relid (\d+)', 'g'))::oid  rel_oid,ev_class --rel_oid 被依赖对象 ,ev_class 视图名称
    from pg_rewrite 
    union 
    select unnest(regexp_matches(ev_action::text,':resorigtbl (\d+)','g'))::oid,ev_class
    from pg_rewrite 
     ) deptbl                   --pg_write获取依赖关系
    inner join pg_class b       --被依赖对象获取表名等信息
    on deptbl.rel_oid = b.oid
    inner join pg_namespace c
    on b.relnamespace = c.oid
    inner join pg_class d     --视图获取视图名等信息,且用于排除pg_write获取的自身对象,即rel_oid <> ev_class
    on deptbl.ev_class = d.oid
    and deptbl.rel_oid <> d.oid
    where  b.relname = 't2' --指定表名t2
union all
    select c.nspname,b.relname,deptbl.rel_oid,b.relkind,d.oid as ori_oid,d.relname ori_name,level+1
    from (
    select unnest(regexp_matches(ev_action::text,':relid (\d+)', 'g'))::oid  rel_oid,ev_class
    from pg_rewrite 
  union 
    select unnest(regexp_matches(ev_action::text,':resorigtbl (\d+)','g'))::oid,ev_class
    from pg_rewrite 
  ) deptbl 
    inner join pg_class b
    on deptbl.rel_oid = b.oid
    inner join pg_namespace c
    on b.relnamespace = c.oid
    inner join pg_class d
    on deptbl.ev_class = d.oid
    and deptbl.rel_oid <> d.oid
    inner join rec_view e          --循环语句关联条件
    on deptbl.rel_oid = e.ori_oid
    where level <=10    --level防止死循环
)
select * from rec_view;

結果から、t2は関連するビューがv2とv3の2つのビューになるためです。

ビューリストを取得したら、gs_dumpを使用して、2つのビューv2とv3をテキストにバックアップします。

gs_dump mydb1 -s -t v2 -t v3 -c -f view.ddl -p 25308

2. テーブル定義をテキストにバックアップ->テキストでテーブル定義を変更->バックアップテーブル(ALTER TABLE XX RENAME TO XX_BAK)->変更されたテーブルを追加してデータを挿入

テーブル定義をテキストにバックアップ:gs_dumpを使用してt2のテーブル構造をファイルにエクスポートします

テキスト内のテーブル定義を変更します。名前のフィールドタイプを元のvarchar(30)からvarchar(50)に変更します。

バックアップテーブル(ALTER TABLE XX RENAME TO XX_BAK):ALTER TABLE RENAME action in the text

変更されたテーブルを追加してデータを挿入する:SQLを追加してテキストにデータを挿入する

gs_dump mydb1 -s -t t2  -f t2.ddl -p 25308

上記の内容を変更すると、結果は次のようになります。

テキストステートメントを実行する

gsql -d mydb1 -p 25308 -r  -f t2.ddl

3、ビューを更新する

エクスポートされたv2、v3ビューを実行する

gsql -d mydb1 -p 25308 -r  -f view.ddl

次に、t2テーブルの定義が変更されているかどうかを確認し、ビューを照会できるかどうかを確認します

\d t2
select * from v2;
select * from v3;

総括する

ビューはテーブルを使用するため、依存関係が存在します。ビューが依存するテーブルの定義を変更する場合、特定の状況下でそれを変更する方法はありません。ここでは、ビュー定義をテキストにバックアップする->テーブル定義をバックアップすることで達成できると思います。テキストに移動->テキストでテーブル定義を変更->バックアップテーブル(ALTER TABLE XX RENAME TO XX_BAK)->変更されたテーブルを追加->データを挿入->バックアップビューテキストリフレッシュビュー

バックアップビューの定義手順では、変更する必要のあるテーブルの関連ビューが何であるかを知る必要があります。このクエリプロセスは、関連するビューを再帰的に取得するために、pg_rewriteテーブルと再帰xxを使用する必要があります。関連するビューを取得してバックアップした後、残りの手順は比較的簡単です。

 

クリックしてフォローし、Huawei Cloudの新しいテクノロジーについて初めて学びます〜

おすすめ

転載: blog.csdn.net/devcloud/article/details/108528596