代码之家  ›  专栏  ›  技术社区  ›  martin.malek

postgres alter表有问题

  •  29
  • martin.malek  · 技术社区  · 15 年前

    我对postgre中的alter表有一个问题。我想更改varchar列的大小。当我尝试这样做时,它说视图依赖于该列。我不能放弃这个观点,因为其他的事情都取决于它。除了放下所有的东西重新创建它,还有其他方法吗?

    我刚找到一个选项,那就是从视图中删除表联接,当我不更改返回的列时,我可以这样做。但是,还有更多的观点需要改变。难道没有什么我能说的,它应该被延迟,并与提交一起检查吗?

    4 回复  |  直到 6 年前
        1
  •  20
  •   Dan LaRocque    15 年前

    我遇到了这个问题,找不到解决办法。不幸的是,据我所知,必须删除视图,更改基础表上的列类型,然后重新创建视图。这完全可以在单个事务中发生。

    约束延迟不适用于这个问题。换句话说,甚至 SET CONSTRAINTS ALL DEFERRED 对这一限制没有影响。具体来说,约束延迟不适用于打印的一致性检查 ERROR: cannot alter type of a column used by a view or rule 当试图改变视图下列的类型时。

        2
  •  9
  •   craigds    13 年前

    如果你不需要改变 类型 在这个领域,但仅仅是它的规模,这种方法应该是有效的:

    从这些表开始:

    CREATE TABLE foo (id integer primary key, names varchar(10));
    CREATE VIEW voo AS (SELECT id, names FROM foo);
    

    \d foo \d voo 两者的长度都显示为10:

    id     | integer               | not null
    names  | character varying(10) | 
    

    现在将长度改为20 pg_attribute 表:

    UPDATE pg_attribute SET atttypmod = 20+4
    WHERE attrelid IN ('foo'::regclass, 'voo'::regclass)
    AND attname = 'names';
    

    (注:20+4是一些疯狂的PostgreSQL遗留物,+4是强制的。)

    现在 D.FO 显示:

    id integer不为空
    名称字符变化(10)|
    

    奖金:这比做得快:

    ALTER TABLE foo ALTER COLUMN names TYPE varchar(20);
    

    从技术上讲,您可以在不更改视图列大小的情况下更改表列的大小,但不能保证会产生什么副作用;最好同时更改这两个列。

    来源和更全面的解释: http://sniptools.com/databases/resize-a-column-in-a-postgresql-table-without-changing-data

        3
  •  6
  •   Hambone    6 年前

    我参加晚会有点晚了,但在这个问题发表几年后,通过下面引用的一篇文章(不是我的——我只是感谢他的才华的受益者)发布了一个出色的解决方案。

    我刚刚在一个在136个独立视图中被引用(第一级)的对象上测试了这一点,并且这些视图中的每一个都在其他视图中被引用。解决方案只需几秒钟。

    因此,请阅读本文并复制粘贴表和列出的两个函数:

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

    实施示例:

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

    错误:无法更改视图或规则详细信息使用的列的类型: 规则“视图返回工具箱”报告。“平均设置成本”取决于 “产品ID”列 **********错误**********

    错误:无法更改视图或规则使用的列的类型

    现在,对于PostgreSQL忍者魔咒:

    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');
    

    --编辑:2018年11月13日--

    上面的链接可能已经死了。这是两个过程的代码:

    存储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)
    );
    

    保存和删除:

    CREATE OR REPLACE FUNCTION util.deps_save_and_drop_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 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$
      LANGUAGE plpgsql VOLATILE
      COST 100;
    

    恢复:

    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;
    
        4
  •  5
  •   bendiy    13 年前

    我今天遇到了这个问题,找到了一个解决方法来避免删除和重新创建视图。我不能直接删除我的视图,因为它是一个主视图,在它上面有许多依赖的视图。除了有一个重建脚本来删除级联,然后重新创建我的所有视图之外,这是一个解决方案。

    我将主视图更改为对有问题的列使用虚拟值,更改了表中的列,并将视图切换回该列。使用如下设置:

    CREATE TABLE base_table
    (
      base_table_id integer,
      base_table_field1 numeric(10,4)
    );
    
    CREATE OR REPLACE VIEW master_view AS 
      SELECT
        base_table_id AS id,
        (base_table_field1 * .01)::numeric AS field1
      FROM base_table;
    
    CREATE OR REPLACE VIEW dependent_view AS 
      SELECT
        id AS dependent_id,
        field1 AS dependent_field1
      FROM master_view;
    

    尝试如下更改基表字段1类型:

    ALTER TABLE base_table ALTER COLUMN base_table_field1 TYPE numeric(10,6);
    

    将出现此错误:

    ERROR:  cannot alter type of a column used by a view or rule
    DETAIL:  rule _RETURN on view master_view depends on column "base_table_field1"
    

    如果将主视图更改为对该列使用虚拟值,如下所示:

    CREATE OR REPLACE VIEW master_view AS 
      SELECT
        base_table_id AS id,
        0.9999 AS field1
      FROM base_table;
    

    然后运行你的更改:

    alter table base_table alter column base_table_field1 type numeric(10,6);
    

    然后切换视图:

    CREATE OR REPLACE VIEW master_view AS 
      SELECT
        base_table_id AS id,
        (base_table_field1 * .01)::numeric AS field1
      FROM base_table;
    

    这完全取决于主视图的显式类型是否不变。因为我的视图使用'(base_table_field1*.01)::numeric as field1'它起作用,但是'base_table_field1 as field1'不会因为列类型改变。这种方法在我这样的情况下可能会有所帮助。