【问题标题】:Cannot update view in PostgreSQL?无法在 PostgreSQL 中更新视图?
【发布时间】:2012-10-20 12:49:54
【问题描述】:

我的网站是使用在 Ubuntu 11.10 上的 Postgresql 8.3 服务器上运行的 Drupal 6 开发的。还有 webmin 版本 1.590。

现在我想更新表中的记录,但是当我运行时:

UPDATE uac_institution_view SET status = '2' WHERE nid = '9950'

它给了我一个类似的错误:

执行 SQL 失败:SQL UPDATE uac_institution_view SET status = '2' WHERE nid = '9950' 失败:错误:无法更新视图提示:您 需要一个无条件的 ON UPDATE DO INSTEAD 规则。

问题是只有SELECT 查询有效。 UPDATEINSERTDELETE 命令不起作用;他们因上述错误而失败。

这是一个权限问题吗?语法错误?还有什么?

【问题讨论】:

  • 第一个错误信息很清楚问题是什么。
  • 您是否阅读了我关于如何提供足够信息的解释性答案,或者它链接到的 PostgreSQL wiki 上的建议? psql \d 输出在哪里? PostgreSQL 版本(1.590 不是 PostgreSQL 版本;如果有疑问,请使用select version())? stackoverflow.com/a/13151381/398670 如果您无法访问uac_institution_view 的 DDL, 将如何回答这个问题?此外,这是与您之前提供的不同的错误消息。有什么变化?

标签: postgresql sql-update sql-view


【解决方案1】:

默认情况下,PostgreSQL 视图不可更新。您必须告诉 PostgreSQL 您希望如何更新视图。

使用“无条件 ON UPDATE DO INSTEAD 规则”(如您粘贴的错误消息所述)或最好在 PostgreSQL 9.1 及更高版本上使用视图触发器执行此操作。我在my answer to your previous post 中提供了所有内容的链接,但这里有更多信息:

在许多情况下,最好将视图保留为只读并只更新基础表。由于您没有提供视图的定义,因此很难说出实际涉及的内容。使用在psql 中运行\d uac_institution_view 的输出更新您的问题,并评论说您已经这样做了;也许我可以指出一种直接在基础表上运行更新的方法。

您使用的是非常过时的 PostgreSQL (8.3) 版本,因此您不能使用首选的INSTEAD OF 触发器方法,您必须使用规则或直接更新基础表。

【讨论】:

  • 对不起我的英语不好,版本是:PostgreSQL 8.3.8 on x86_64-pc-linux-gnu,由 GCC gcc-4.4.real (Ubuntu 4.4.1-3ubuntu3) 4.4.1 和\d 的输出是:Failed to execute SQL : Command Unsupported。感谢您的回复。
  • @srnu 你的英语比我对你的语言的掌握要好。没关系。您正在使用一个非常旧的 PostgreSQL 版本,您应该计划尽快升级。它不支持INSTEAD OF 触发器,因此您必须使用规则来实现对视图的更新支持,或者直接使用UPDATE 基础表。我无法向您展示如何做到这一点,因为您仍然未能提供视图的定义! (答案已更新)
  • 您好先生,我是postgresql db的新手,如何查看视图的定义以及如何查看表的结构。
  • @srnu 连接图形 PgAdmin-III 程序并检查那里的视图/表,或者(最好是 Stack Overflow)打开psql 命令行工具,连接到所需的数据库,并运行\d view_or_table_name,然后复制并粘贴输出。请参阅 postgresql.org/docs/current/interactive/app-psql.htmlpostgresql.org/docs/current/interactive/tutorial.html 。您可能需要考虑聘请某人在某个时候帮助您将应用程序和数据库升级到当前版本;见postgresql.org/support/professional_support
  • 您可能需要补充一点,因为 9.3 简单视图可以自动更新:postgresql.org/docs/current/static/…
【解决方案2】:

仅供参考,在发布涉及规则/触发器的答案后,PostgreSQL 9.3 推出了可自动更新的视图。截至 2013 年 6 月 27 日,9.3 版处于 beta 2 阶段,因此尚未正式发布。

这里是一个例子:https://web.archive.org/web/20160322164044/http://michael.otacoo.com/postgresql-2/postgres-9-3-feature-highlight-auto-updatable-views/

【讨论】:

    【解决方案3】:

    我使用的是 postgres 9.5,默认情况下视图是可更新的。 示例:

    CREATE TABLE UP_DATE (id number, name varchar2(29));
    insert into up_date values(1, 'Foo');
    select * from up_date;
    CREATE OR REPLACE VIEW UPDATE
    AS
    Select 
    name from up_date;
    select * from update;
    insert into update values('Bar');
    select * from update;
    

    会放出 Foo 和 Bar

    【讨论】:

    • 仅供参考 - 如果您使用“CREATE OR REPLACE”添加列,则必须将新列添加到所选列列表的末尾。
    • 数据类型 NUMBERVARCHAR2 是 Oracle 特定的 - 它应该是 NUMERICVARCHAR (n)。你可能想改变它?
    【解决方案4】:

    正如 Jeff French 所指出的,从 PG 9.3 开始,一切都可以正常工作...除了一些例外情况(更多信息见下文)。

    简单示例

    您可以在 PostgreSQL 上测试此代码。完成后使用级联删除(与表格一起删除视图)。

    -- create table
    --DROP TABLE user_table CASCADE;
    CREATE TABLE user_table (
        id serial,
        lastname varchar(100),
        user_type varchar(2) DEFAULT 'nn',
        PRIMARY KEY (id)
    );
    -- initial data
    INSERT INTO user_table(lastname) VALUES('Foo');
    SELECT * FROM user_table;
    
    -- simple view (note, no id here)
    CREATE OR REPLACE VIEW user_view
    AS
        SELECT lastname, user_type 
        FROM user_table
    ;
    
    -- check view (will have initial data)
    SELECT * FROM user_view;
    
    -- insert into user_table via view
    INSERT INTO user_view VALUES('Bar');
    -- check (both will have both records)
    SELECT * FROM user_view;
    SELECT * FROM user_table;
    -- you can run above many times
    -- (id will auto-increment even though it is not in the view)
    
    -- update user_table via view
    UPDATE user_view SET user_type='v' WHERE lastname = 'Bar';
    SELECT * FROM user_table;
    

    限制

    不过有一些限制,这取决于你的 PG 版本。

    • PG 9.3 views 中不能有任何表达式等。也只允许一个表...所以或多或少是一个简单的选择限制、重新排序或重命名列。
    • PG 9.4 views 中可以部分更新。所以你可以有表达,但你不能更新它们(至少不是开箱即用的)。

    如果您的视图中有WHERE,那么您可能会得到一些奇怪的结果。所以这仍然适用于插入:

    CREATE OR REPLACE VIEW user_view
    AS
        SELECT lastname as last_name, user_type
        FROM user_table
        WHERE user_type = 'v'
    ;
    INSERT INTO user_view VALUES('Bar');
    

    但更新可能不起作用。至少这不会起作用,因为它将更新 0 行:

    UPDATE user_view SET user_type='v';
    

    因为实际上这等同于以下查询(如果您考虑一下,这很有意义):

    UPDATE user_view SET user_type='v' WHERE user_type = 'v';
    

    我想知道他们是否会在某个时候支持联接...但是在撰写本文时,PG 14 已经发布,并且它不支持在视图中加入表格(我的意思是更新)。

    替代方案

    您仍然可以使用INSTEAD OF 触发器,尤其是对于更复杂的视图。而且您可以使用规则...但是(如 CREATE RULE docs 中所述)自动更新的视图会比手动创建的规则更快。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-25
      • 2023-02-07
      • 1970-01-01
      • 2019-02-02
      • 2023-04-02
      • 2020-09-07
      • 2022-11-30
      • 1970-01-01
      相关资源
      最近更新 更多