46

postgre の ALTER TABLE に問題が 1 つあります。varchar 列のサイズを変更したい。これを行おうとすると、ビューがその列に依存していると表示されます。ビューを削除することはできません。他のものがビューに依存しているためです。すべてを落として作り直す以外に方法はありませんか?

返された列を変更しない場合は、ビューからテーブル結合を削除するオプションが1つ見つかりました。それを行うことができます。それでも、変更する必要があるビューは他にもあります。延期してコミットでチェックする必要があるとは言えませんか?

4

5 に答える 5

33

私はこの問題に遭遇しましたが、それを回避する方法が見つかりませんでした。残念ながら、私が知る限り、ビューを削除し、基になるテーブルの列の型を変更してから、ビューを再作成する必要があります。これは、1 つのトランザクションで完全に発生する可能性があります。

制約の延期は、この問題には適用されません。つまり、evenSET CONSTRAINTS ALL DEFERREDはこの制限に影響を与えません。具体的にはERROR: cannot alter type of a column used by a view or rule、ビューの基になる列の型を変更しようとしたときに出力される一貫性チェックには、制約の延期は適用されません。

于 2010-07-14T08:30:16.867 に答える
28

私はパーティーに少し遅れていますが、この質問が投稿されてから数年後、以下で参照されている記事を介して素晴らしい解決策が投稿されました(私のものではありません-私は単に彼の才能に感謝しています)。

136 個の個別のビューで (第 1 レベルで) 参照されているオブジェクトでこれをテストしたところ、これらの各ビューは他のビューで参照されています。ソリューションはわずか数秒で実行されました。

したがって、この記事を読み、リストされている表と 2 つの関数をコピーして貼り付けます。

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

エラー: ビューまたはルールで使用される列のタイプを変更できません 詳細: ビュー toolbox_reporting のルール _RETURN."Average_setcost" は列 "prod_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 日編集 --

上記のリンクは無効になっている可能性があります。2 つの手順のコードは次のとおりです。

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

保存してドロップ:

-- 2020 年 8 月 28 日編集 -- -- これは Pg12 で動作しなくなりました。p_view_schema と p_view_name のパラメーターを varchar から 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$

戻す:

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;
于 2018-02-27T02:49:19.770 に答える
16

フィールドのタイプを変更する必要がなく、サイズだけを変更する必要がある場合は、次のアプローチが機能するはずです。

次の表から始めます。

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

pg_attributeテーブルの長さを 20 に変更します。

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

(注: 20+4 は、クレイジーな postgresql レガシーのものであり、+4 は必須です。)

現在\d fooは次のように表示されます:

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

ボーナス:それは行うよりもずっと速かった:

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

技術的には、ビューの列のサイズを変更せずにテーブルの列のサイズを変更できますが、どのような副作用があるかは保証されません。両方を一度に変更するのがおそらく最善です。

ソースと詳細な説明: http://sniptools.com/databases/resize-a-column-in-a-postgresql-table-without-ching-data

于 2012-03-23T15:28:58.447 に答える
7

今日、この問題に遭遇し、回避策を見つけて、 VIEW の削除と再作成を回避しました。VIEW はマスター VIEW であり、その上に多数の従属 VIEW が構築されているため、単純に VIEW を削除することはできません。DROP CASCADE を作成してすべての VIEW を再作成するための再構築スクリプトを用意する以外に、これは回避策です。

問題のある列にダミー値を使用するようにマスター VIEW を変更し、テーブル内の列を変更して、VIEW を元の列に切り替えました。次のようなセットアップを使用します。

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;

次のように base_table_field1 タイプを変更しようとしています:

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"

master_view を次のように列にダミー値を使用するように変更した場合:

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

次に、alter を実行します。

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;

master_view に変更されない明示的な型があるかどうかによって異なります。私の VIEW は '(base_table_field1 * .01)::numeric AS field1' を使用するため、機能しますが、列の型が変更されるため、'base_table_field1 AS field1' は機能しません。このアプローチは、私のような場合に役立つ場合があります。

于 2011-10-11T21:39:42.863 に答える