【问题标题】:Changing the type of a column used in other views更改其他视图中使用的列的类型
【发布时间】:2012-03-31 11:16:13
【问题描述】:
create table base (name character varying(255));                                                                                                                                                        
create view v1 as select *, now() from base;                                                        
create view v2 as select * from v1 where name = 'joe';
alter table base alter column name type text;                                                       

给出这个错误:

cannot alter type of a column used by a view or rule
DETAIL:  rule _RETURN on view v1 depends on column "name"

这有点烦人,因为现在我必须重新创建所有引用 base.name 列的视图。当我的视图引用其他视图时,这尤其令人讨厌。

我希望能够做的事情是这样的:

select recreate_views('v1', 'v2', 'alter table base alter column name type text');

让函数获取 v1 和 v2 的视图定义,删除它们,运行指定的代码,然后重新创建 v1 和 v2。如果我可以使用 Ruby,我可能会让函数采用函数/块/lambda,比如

recreate_views 'v1', 'v2' do
  alter table base alter column name type text
end

这样的事情可能吗?有没有做类似事情的实用程序?

【问题讨论】:

  • select definition from pg_views where viewname ='v1'; 为您提供视图定义

标签: postgresql views


【解决方案1】:

我认为这可以满足您的需求,尽管我将视图列表移到了 args 的末尾以与 VARIADIC 语义兼容。

CREATE OR REPLACE FUNCTION recreate_views(run_me text, VARIADIC views text[])
  RETURNS void
AS  $$
DECLARE
  view_defs text[];
  i integer;
  def text;
BEGIN
  for i in array_lower(views,1) .. array_upper(views,1) loop
    select definition into def from pg_views where viewname = views[i];
    view_defs[i] := def;
    EXECUTE 'DROP VIEW ' || views[i];
  end loop;

  EXECUTE run_me;

  for i in reverse array_upper(views,1) .. array_lower(views,1) loop
    def = 'CREATE OR REPLACE VIEW ' || quote_ident( views[i] ) || ' AS ' || view_defs[i];
    EXECUTE def;
  end loop;

END
$$
LANGUAGE plpgsql;

【讨论】:

  • 为了更完整,可以弄清楚如何查询哪些视图取决于您正在修改的表并使用该查询而不是枚举视图名称。需要了解 pg_rewrite | pg_rule 这样做,我想。
  • 很有趣,谢谢。我还有几个 postgresql 函数也需要删除和重新创建。我想我可以用类似的方法做到这一点。
  • 我认为视图需要按照它们被删除的相反顺序创建(如果某些视图依赖于其他视图)。
  • 我编辑了函数以从 drop 的相反顺序创建。如果视图相互依赖,则调用需要以相反的依赖顺序指定它们
  • 谢谢!我想我编辑了你的答案,在你做完之后几秒钟就包含了相同的代码。
【解决方案2】:

一个改进是在尝试删除视图之前检查它是否存在,否则你会得到一个错误,所以这样做:

for i in array_lower(views,1) .. array_upper(views,1) loop
    select definition into def from pg_views where viewname = views[i];
    view_defs[i] := def;
    IF def IS NOT NULL THEN
        EXECUTE 'DROP VIEW ' || schema_name || '.' || views[i];
    END IF;
end loop;   

    EXECUTE run_me;

for i in reverse array_upper(views,1) .. array_lower(views,1) loop
    IF view_defs[i] IS NOT NULL THEN
        def = 'CREATE OR REPLACE VIEW ' || schema_name || '.' || views[i] || ' AS ' || view_defs[i];
        EXECUTE def;
    END IF;
end loop;

【讨论】:

    猜你喜欢
    • 2016-09-04
    • 2020-09-03
    • 2011-01-10
    • 1970-01-01
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多