无法更新 PostgreSQL 中的视图?

问题描述 投票:0回答:5

我的网站是使用运行在 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
查询有效。
UPDATE
INSERT
DELETE
命令不起作用;他们因上述错误而失败。

这是权限问题吗?语法错误?还有别的吗?

sql database postgresql sql-update sql-view
5个回答
25
投票

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

使用“无条件

ON UPDATE DO INSTEAD
规则”(如您粘贴的错误消息所述)执行此操作,或者最好在 PostgreSQL 9.1 及更高版本上使用视图触发器。我在我对您上一篇文章的回答中提供了所有内容的链接,但这里有更多信息:

在许多情况下,最好将视图保留为只读并仅更新基础表。由于您没有提供视图的定义,因此很难说出它实际上涉及什么。使用在

\d uac_institution_view
中运行
psql
的输出更新您的问题,并评论说您已经这样做了;也许我可以指出一种直接在基础表上运行更新的方法。

您使用的是非常过时的 PostgreSQL 版本 (8.3),因此您无法使用首选的

INSTEAD OF
触发器方法,您必须使用规则或直接更新基础表。


8
投票

仅供参考,在发布涉及规则/触发器的答案后,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 /


6
投票

我使用的是 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


0
投票

正如 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 视图中不能有任何表达式等。也只允许一个表...所以或多或少是一个简单的选择限制、重新排序或重命名列。
  • PG 9.4 视图 中可以部分更新。所以你可以有表达,但你将无法更新它们(至少不是开箱即用的)。

如果您认为有

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 文档中所述)自动更新视图将比手动创建规则更快。


0
投票

您可以对视图进行

INSERT
UPDATE
DELETE
操作。

例如,您创建

person
表,如下所示:

CREATE TABLE person (
  id INTEGER,
  first_name VARCHAR(20),
  last_name VARCHAR(20),
  age INTEGER
);

然后,将 2 行插入到

person
表中,如下所示:

INSERT INTO person (id, first_name, last_name, age) 
VALUES (1, 'John', 'Smith', 27), (2, 'David', 'Miller', 32);

然后,您创建

my_view
视图,如下所示:

CREATE VIEW my_view AS
  SELECT first_name, age FROM person;

然后调用

my_view
得到如下所示的结果。 *
id
last_name
不可用:

postgres=# SELECT * FROM my_view;
 first_name | age
------------+-----
 John       |  27
 David      |  32
(2 rows)

现在,您可以使用

person
my_view
表插入 2 行,如下所示。 *
id
last_name
不可用:

INSERT INTO my_view (first_name, age) 
VALUES ('Robert', 18), ('Mark', 40);

然后,将 2 行插入到

person
表中,如下所示:

postgres=# SELECT * FROM person;
 id | first_name | last_name | age
----+------------+-----------+-----
  1 | John       | Smith     |  27
  2 | David      | Miller    |  32
    | Robert     |           |  18
    | Mark       |           |  40
(4 rows)

并且,您可以使用

person
更新
my_view
表,如下所示。 *
id
last_name
不可用:

UPDATE my_view SET first_name = 'Tom' WHERE age = 32;

然后,

person
表更新如下:

postgres=# SELECT * FROM person;
 id | first_name | last_name | age
----+------------+-----------+-----
  1 | John       | Smith     |  27
    | Robert     |           |  18
    | Mark       |           |  40
  2 | Tom        | Miller    |  32
(4 rows)

并且,您可以使用

person
my_view
表中删除 2 行,如下所示。 *
id
last_name
不可用:

DELETE FROM my_view WHERE age = 18 OR age = 40;

然后,从

person
表中删除2行,如下所示:

postgres=# SELECT * FROM person;
 id | first_name | last_name | age
----+------------+-----------+-----
  1 | John       | Smith     |  27
  2 | Tom        | Miller    |  32
(2 rows)
© www.soinside.com 2019 - 2024. All rights reserved.