Problem with Postgres ALTER TABLE

后端 未结 4 1946
死守一世寂寞
死守一世寂寞 2021-02-02 06:47

I have one problem with the ALTER TABLE in postgre. I want to change size of the varchar column. When I try to do this, It says that the view is dependent on that column. I can\

4条回答
  •  渐次进展
    2021-02-02 07:17

    I'm a little late to the party, but years after this question was posted, a brilliant solution was posted via an article referenced below (not mine -- I'm simply a thankful beneficiary of his brilliance).

    I just tested this on an object that is referenced (on the first level) in 136 separate views, and each of those views is referenced in other views. The solution ran in mere seconds.

    So, read this article and copy and paste the table and two functions listed:

    http://mwenus.blogspot.com/2014/04/postgresql-how-to-handle-table-and-view.html

    Implementation example:

    alter table mdm.global_item_master_swap
    alter column prod_id type varchar(128),
    alter column prod_nme type varchar(512);
    

    ERROR: cannot alter type of a column used by a view or rule DETAIL: rule _RETURN on view toolbox_reporting."Average_setcost" depends on column "prod_id" ********** Error **********

    ERROR: cannot alter type of a column used by a view or rule

    And now for the PostgreSQL ninja's magic:

    select util.deps_save_and_drop_dependencies('mdm', 'global_item_master_swap');
    
    
    alter table mdm.global_item_master_swap
    alter column prod_id type varchar(128),
    alter column prod_nme type varchar(512);
    
    
    select util.deps_restore_dependencies('mdm', 'global_item_master_swap');
    

    -- EDIT 11/13/2018 --

    It appears the link above might be dead. Here is the code for the two procedures:

    Table that stores DDL:

    CREATE TABLE util.deps_saved_ddl
    (
      deps_id serial NOT NULL,
      deps_view_schema character varying(255),
      deps_view_name character varying(255),
      deps_ddl_to_run text,
      CONSTRAINT deps_saved_ddl_pkey PRIMARY KEY (deps_id)
    );
    

    Save and Drop:

    -- Edit 8/28/2020 -- -- This stopped working with Pg12. The fix is below to change the parameters of p_view_schema and p_view_name from varchar to name:

    CREATE OR REPLACE FUNCTION util.deps_save_and_drop_dependencies(
        p_view_schema name, p_view_name name)
        RETURNS void
        LANGUAGE plpgsql
        COST 100
    AS $BODY$
    
    declare
      v_curr record;
    begin
    for v_curr in 
    (
      select obj_schema, obj_name, obj_type from
      (
      with recursive recursive_deps(obj_schema, obj_name, obj_type, depth) as 
      (
        select p_view_schema, p_view_name, null::varchar, 0
        union
        select dep_schema::varchar, dep_name::varchar, dep_type::varchar, recursive_deps.depth + 1 from 
        (
          select ref_nsp.nspname ref_schema, ref_cl.relname ref_name, 
          rwr_cl.relkind dep_type,
          rwr_nsp.nspname dep_schema,
          rwr_cl.relname dep_name
          from pg_depend dep
          join pg_class ref_cl on dep.refobjid = ref_cl.oid
          join pg_namespace ref_nsp on ref_cl.relnamespace = ref_nsp.oid
          join pg_rewrite rwr on dep.objid = rwr.oid
          join pg_class rwr_cl on rwr.ev_class = rwr_cl.oid
          join pg_namespace rwr_nsp on rwr_cl.relnamespace = rwr_nsp.oid
          where dep.deptype = 'n'
          and dep.classid = 'pg_rewrite'::regclass
        ) deps
        join recursive_deps on deps.ref_schema = recursive_deps.obj_schema and deps.ref_name = recursive_deps.obj_name
        where (deps.ref_schema != deps.dep_schema or deps.ref_name != deps.dep_name)
      )
      select obj_schema, obj_name, obj_type, depth
      from recursive_deps 
      where depth > 0
      ) t
      group by obj_schema, obj_name, obj_type
      order by max(depth) desc
    ) loop
    
      insert into util.deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
      select p_view_schema, p_view_name, 'COMMENT ON ' ||
      case
      when c.relkind = 'v' then 'VIEW'
      when c.relkind = 'm' then 'MATERIALIZED VIEW'
      else ''
      end
      || ' ' || n.nspname || '.' || c.relname || ' IS ''' || replace(d.description, '''', '''''') || ''';'
      from pg_class c
      join pg_namespace n on n.oid = c.relnamespace
      join pg_description d on d.objoid = c.oid and d.objsubid = 0
      where n.nspname = v_curr.obj_schema and c.relname = v_curr.obj_name and d.description is not null;
    
      insert into util.deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
      select p_view_schema, p_view_name, 'COMMENT ON COLUMN ' || n.nspname || '.' || c.relname || '.' || a.attname || ' IS ''' || replace(d.description, '''', '''''') || ''';'
      from pg_class c
      join pg_attribute a on c.oid = a.attrelid
      join pg_namespace n on n.oid = c.relnamespace
      join pg_description d on d.objoid = c.oid and d.objsubid = a.attnum
      where n.nspname = v_curr.obj_schema and c.relname = v_curr.obj_name and d.description is not null;
      
      insert into util.deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
      select p_view_schema, p_view_name, 'GRANT ' || privilege_type || ' ON ' || table_schema || '.' || table_name || ' TO ' || grantee
      from information_schema.role_table_grants
      where table_schema = v_curr.obj_schema and table_name = v_curr.obj_name;
      
      if v_curr.obj_type = 'v' then
        insert into util.deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
        select p_view_schema, p_view_name, 'CREATE VIEW ' || v_curr.obj_schema || '.' || v_curr.obj_name || ' AS ' || view_definition
        from information_schema.views
        where table_schema = v_curr.obj_schema and table_name = v_curr.obj_name;
      elsif v_curr.obj_type = 'm' then
        insert into util.deps_saved_ddl(deps_view_schema, deps_view_name, deps_ddl_to_run)
        select p_view_schema, p_view_name, 'CREATE MATERIALIZED VIEW ' || v_curr.obj_schema || '.' || v_curr.obj_name || ' AS ' || definition
        from pg_matviews
        where schemaname = v_curr.obj_schema and matviewname = v_curr.obj_name;
      end if;
      
      execute 'DROP ' ||
      case 
        when v_curr.obj_type = 'v' then 'VIEW'
        when v_curr.obj_type = 'm' then 'MATERIALIZED VIEW'
      end
      || ' ' || v_curr.obj_schema || '.' || v_curr.obj_name;
      
    end loop;
    end;
    $BODY$
    

    Restore:

    CREATE OR REPLACE FUNCTION util.deps_restore_dependencies(
        p_view_schema character varying,
        p_view_name character varying)
      RETURNS void AS
    $BODY$
    declare
      v_curr record;
    begin
    for v_curr in 
    (
      select deps_ddl_to_run 
      from util.deps_saved_ddl
      where deps_view_schema = p_view_schema and deps_view_name = p_view_name
      order by deps_id desc
    ) loop
      execute v_curr.deps_ddl_to_run;
    end loop;
    delete from util.deps_saved_ddl
    where deps_view_schema = p_view_schema and deps_view_name = p_view_name;
    end;
    $BODY$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    

提交回复
热议问题