PostgreSQL:删除列并重新创建依赖视图

Posted

技术标签:

【中文标题】PostgreSQL:删除列并重新创建依赖视图【英文标题】:PostgreSQL: Drop column and recreate dependent views 【发布时间】:2018-10-31 12:04:54 【问题描述】:

我创建了下面的测试表和依赖视图。

create table test_col_drp (col1 varchar(100), col2 varchar(100), col3 varchar(100));
create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1, col3 col3_vw1 from test_col_drp;
create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2, col3_vw1 col3_vw2 from test_col_drp_vw1;

我正在尝试从表中删除一列,但出现以下错误:

alter table test_col_drp drop column col3;

ERROR:  cannot drop table test_col_drp column col3 because other objects depend on it
DETAIL:  view test_col_drp_vw1 depends on table test_col_drp column col3 view test_col_drp_vw2 depends on view test_col_drp_vw1
HINT:  Use DROP ... CASCADE to drop the dependent objects too.
********** Error **********

删除列并重新创建所有依赖视图的最佳方法是什么?

工作: x86_64-pc-mingw64 上的 PostgreSQL 9.6.6,由 gcc.exe 编译(Rev5,由 MSYS2 项目构建)4.9.2,64 位

Windows 10

【问题讨论】:

对于您的示例,您不能只是“重新创建”视图,您应该删除现有视图并创建另一个可能具有相同名称和不同列的视图(通常具有不同的主体)。不确定它是否可以至少以简单的方式自动化,特别是如果您要删除的列参与逻辑。 postgresqltutorial.com/postgresql-drop-column 关于如何删除具有依赖视图的列的指南。然后正如蒂亚戈指出的那样,您需要重新创建它们。 【参考方案1】:

首先,您必须删除视图。然后,执行 alter table,最后再次创建视图。见:

  -- This is what you have in your database  

 create table test_col_drp (col1 varchar(100), col2 varchar(100), col3 varchar(100));
 create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1, col3 col3_vw1 from test_col_drp;
 create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2, col3_vw1 col3_vw2 from test_col_drp_vw1;

-- drop views and alter table
drop view test_col_drp_vw2;
drop view test_col_drp_vw1;

alter table test_col_drp drop column col3;

-- creating the views again without col3
create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1 from test_col_drp;
create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2 from test_col_drp_vw1;

另一种方法是使用drop cascade。在这种情况下,您不需要单独删除每个视图,但仍需要重新创建它们:

alter table test_col_drp drop column col3 cascade;

--  creating the views again without col3
create view test_col_drp_vw1 as select col1 col1_vw1, col2 col2_vw1 from test_col_drp;
create view test_col_drp_vw2 as select col1_vw1 col1_vw2, col2_vw1 col2_vw2 from test_col_drp_vw1;

另一种选择是创建一个 SQL 命令,使用 cascade 和 create 视图生成您的 alter table:

with query_result as (
    SELECT dependent_ns.nspname as dependent_schema
    , dependent_view.relname as dependent_view 
    , source_ns.nspname as source_schema
    , source_table.relname as source_table
    , pg_attribute.attname as column_name
    , row_number() over() as id
    FROM pg_depend 
    JOIN pg_rewrite ON pg_depend.objid = pg_rewrite.oid 
    JOIN pg_class as dependent_view ON pg_rewrite.ev_class = dependent_view.oid 
    JOIN pg_class as source_table ON pg_depend.refobjid = source_table.oid 
    JOIN pg_attribute ON pg_depend.refobjid = pg_attribute.attrelid 
        AND pg_depend.refobjsubid = pg_attribute.attnum 
    JOIN pg_namespace dependent_ns ON dependent_ns.oid = dependent_view.relnamespace
    JOIN pg_namespace source_ns ON source_ns.oid = source_table.relnamespace

    WHERE 1=1
    -- AND source_ns.nspname = 'public'
    AND source_table.relname like 'test_col_drp%'
    AND pg_attribute.attnum > 0 
    AND pg_attribute.attname = 'col3'
) 

select concat('alter table ', source_table, ' drop column ' , column_name, ' cascade;' ) as sql_command from query_result where id = 1
union all
select concat('create or replace view ', dependent_view, ' as select * from ', source_table, ';') as  sql_command from query_result  

然后,输出将是:

alter table test_col_drp drop column col3 cascade;
create or replace view test_col_drp_vw1 as select * from test_col_drp;
create or replace view test_col_drp_vw2 as select * from test_col_drp_vw1;

【讨论】:

以上是关于PostgreSQL:删除列并重新创建依赖视图的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 删除视图(如果存在)

PostgreSQL表依赖性跟踪

如何将时间戳字段转换为 int8?或者只是删除该列并创建一个新列?

为 CASCADE 之后的视图重新创建创建数据库视图依赖关系树

创建触发器以重新排序列并修改语句级别

使用docker compose部署postgreSQL数据库