我在postgre中的ALTER TABLE有一个问题。我想改变varchar列的大小。当我尝试这样做时,它表示视图依赖于该列。我不能放弃视图,因为其他东西依赖于它。除了丢弃所有内容并重新创建它之外,还有其他方法吗?
我刚刚找到一个选项,即从视图中删除表连接,当我不更改返回的列时,我可以这样做。但是,我还需要改变更多的观点。是不是有什么可以说它应该延迟并用提交检查?
答案 0 :(得分:22)
我遇到了这个问题,无法找到解决方法。不幸的是,正如我所知,必须删除视图,更改基础表上的列类型,然后重新创建视图。这可以完全在一次交易中发生。
约束延迟不适用于此问题。换句话说,即使SET CONSTRAINTS ALL DEFERRED
也不会对此限制产生影响。具体而言,约束延迟不适用于在尝试更改视图下方的列类型时打印ERROR: cannot alter type of a column used by a view or rule
的一致性检查。
答案 1 :(得分:10)
如果您不需要更改字段的类型,只需更改字段的大小,则此方法应该有效:
从这些表开始:
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(10) |
奖金:这比做的更快:
ALTER TABLE foo ALTER COLUMN names TYPE varchar(20);
从技术上讲,您可以在不更改视图列大小的情况下更改表列的大小,但不保证会产生哪些副作用;最好一次改变它们。
来源和更全面的解释:http://sniptools.com/databases/resize-a-column-in-a-postgresql-table-without-changing-data
答案 2 :(得分:9)
我对派对来说已经很晚了,但是在这个问题发布多年之后,通过下面引用的文章发布了一个出色的解决方案(不是我的 - 我只是他辉煌的感恩之家)
我刚刚在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);
错误:无法更改视图或规则详细信息所使用的列的类型: 在视图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');
- 编辑11/13/2018 -
看来上面的链接可能已经死了。以下是两个程序的代码:
存储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;
答案 3 :(得分:6)
我今天遇到了这个问题并找到了解决方法,以避免丢弃和重新创建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'不会,因为列类型会改变。在某些情况下,这种方法可能会有所帮助。
答案 4 :(得分:1)
我想对第二个答案发表评论,但不能,因为我对 stackoverflow 来说太新了,所以这里是我的评论: 对于那些对该答案中提到的原始文章感兴趣的人来说,blogspot 条目不再可用,但回溯机器仍将其存储:https://web.archive.org/web/20180323155900/http://mwenus.blogspot.com/2014/04/postgresql-how-to-handle-table-and-view.html 这是文章本身,以防archive.org在未来某个时间点被关闭: 2014-04-22 PostgreSQL:如何处理表和视图依赖 PostgreSQL 在修改现有对象方面非常严格。通常,当您尝试 ALTER TABLE 或 REPLACE VIEW 时,它会告诉您不能这样做,因为还有另一个对象(通常是视图或物化视图),这取决于您要修改的对象。似乎唯一的解决方案是删除依赖对象,对目标对象进行所需的更改,然后重新创建删除的对象。
繁琐繁琐,因为那些依赖的对象可以有进一步的依赖,也可能有其他的依赖等等。我创建了 utility functions,它可以在这种情况下提供帮助。
用法很简单——你只需要调用: 选择 deps_save_and_drop_dependencies(p_schema_name, p_object_name); 您必须传递两个参数:模式的名称和该模式中对象的名称。该对象可以是表、视图或物化视图。该函数将删除依赖于 p_schema_name.p_object_name 的所有视图和物化视图,并保存将它们恢复到帮助表中的 DDL。
当你想恢复那些被丢弃的对象时(例如当你完成修改 p_schema_name.p_object_name 时),你只需要再做一个简单的调用: 选择 deps_restore_dependencies(p_schema_name, p_object_name); 并且丢弃的对象将被重新创建。
这些函数负责: 依赖层次结构 跨层次结构删除和创建视图/物化视图的正确顺序 恢复对视图/物化视图的评论和授权 Click here for a working sqlfiddle example 或查看 this gist 以获得完整的源代码。
作者:Mateusz Wenus o 19:32