PostgreSQL: 从视图中删除列

我有一个视图,我正在尝试为其创建一个演化脚本,以便我可以添加一列。这部分工作得很好;列被成功添加了。然而,相反的操作却不起作用;删除最后添加的列时出现了一个“ERROR: cannot drop columns from view”的错误消息。问题在于这个特定的视图有许多引用,既有来自其他对象的引用,也有对其他对象的引用,因此我不能简单地使用“DROP CASCADE”命令来删除它! 为什么我不能从给定的视图中删除新添加的列?那么,我该如何完成这个任务呢? (注意:这里的情况是如此,但我完全可以想象在许多其他情况下也会遇到类似的情况,即从视图中删除列。)

你是如何一开始添加这个列的?你不能使用ALTER VIEW ... ADD COLUMN。你是使用CREATE OR REPLACE VIEW吗?请展示你的代码。 - Craig Ringer
@CraigRinger,是的,CREATE OR REPLACE VIEW与相同的定义,只是多了一列(因为引用的表添加了新列,所以视图必须包含它)。"devolution"从引用的表中移除了该列,因此VIEW也必须不再返回它。 - Yanick Rochon
1个回答

PostgreSQL(至少到9.4版本为止)目前不支持使用CREATE OR REPLACE VIEW删除列。

新查询必须生成与现有视图查询生成的相同列(即相同的列名、相同的顺序和相同的数据类型),但可以在列表末尾添加附加列。

没有根本原因不能添加删除列的支持,但目前还没有人做到实现它所需的工作。

CREATE OR REPLACE VIEW必须递归扫描所有依赖项,并确保其中没有引用要删除的列。如果它们使用了SELECT *,则必须从依赖项中的*扩展中删除该列,然后再扫描它的依赖项。这需要一些工作量,并且在某些情况下,删除列的行为如何与转储和重新加载进行交互方面还不太清楚。因此,目前还没有人希望实现这个功能。欢迎提供补丁和/或开发赞助。

你需要删除这个视图以及依赖于它的所有内容,然后重新创建它和它的依赖项。(添加列到视图也是同样的情况;在8.4版本中引入了对添加列的支持)。 需要注意的是,通常情况下DDL操作是不可逆的。"还原"的概念实际上是有缺陷的。例如,如果你删除了一个列,然后再次添加它,数据仍然会丢失。

3所以,你的意思是,每当一个具有复杂关系的大型应用程序需要更改列时,就需要重新创建整个(或至少大部分)DDL吗?我对PostgreSQL没有太多经验,但从MySQL来看,我从来没有遇到过这样的问题(无论是Oracle、SQL Server还是MySQL),而且对我来说,无法简单地进行更改并在执行时抛出错误(如果有的话)似乎很奇怪。这种限制相当严格。 - Yanick Rochon
@YanickRochon 是的,这确实很痛苦,我也希望看到它得到改进。如果你想帮助实现这一目标,请考虑资助相关工作;请查看 http://www.postgresql.org/support/professional_support/ 。 - Craig Ringer
我们太小了,无法为这样的企业提供资金。但很高兴看到这不是一个固定的话题。 - Yanick Rochon
2@YanickRochon 好吧,这个问题已经在待办事项中了 - "当底层表发生变化时允许重新编译视图/规则",https://wiki.postgresql.org/wiki/Todo#Views_and_Rules。 - Craig Ringer