从可更新视图返回数据不起作用?

时间:2015-05-09 07:34:54

标签: postgresql

我有两个简单的表personaddress,其中插入了一个可更新的视图person_details

关系和触发器

CREATE TABLE address (
  id          serial PRIMARY KEY,
  street      varchar,
  town        varchar NOT NULL
);

CREATE TABLE person (
  id          serial PRIMARY KEY,
  first_name  varchar,
  family_name varchar NOT NULL,
  address     integer REFERENCES address
);

所有者显然拥有完全权限,但普通用户只能通过包含两个表中详细信息的视图访问数据:

CREATE VIEW person_details AS
  SELECT p.id, p.first_name, p.family_name, a.street, a.town
  FROM person p
  LEFT JOIN address a ON a.id = p.address;

视图是可更新的,以便常规用户可以INSERT进入视图底层的表:

GRANT SELECT, INSERT ON person_details TO public;

我已经定义了将INSERT传播到表格的触发器,一切正常:

CREATE FUNCTION t0ii_person_details() RETURNS trigger AS $$
DECLARE
  addr  integer;
BEGIN
  -- Want at least a town to insert anything into table address.
  IF (NEW.town IS NOT NULL) THEN
    INSERT INTO address(street, town)
      VALUES (NEW.street, NEW.town)
      RETURNING id INTO addr;
  ELSE
    addr := NULL;
  END IF;

  INSERT INTO person(first_name, family_name, address)
    VALUES (NEW.first_name, NEW.family_name, addr);
  RETURN NEW;
END; $$ LANGUAGE plpgsql SECURITY DEFINER;

CREATE TRIGGER t0ii_person_details
  INSTEAD OF INSERT ON person_details
  FOR EACH ROW EXECUTE PROCEDURE t0ii_person_details();

INSERT - 确定

一个简单的插入:

pfams=# INSERT INTO person_details (first_name, family_name, town) VALUES ('John', 'Doe', 'Eders');
INSERT 0 1

pfams=# SELECT * FROM person_details;
 id | first_name | family_name | street |  town
----+------------+-------------+--------+--------
  1 | John       | Doe         |        | Eders
(1 row)

INSERT RETURNING id - not ok

但是,如果我想直接从{{1}返回新分配的id(来自person表,它是从序列生成的serial数据类型)声明,然后我什么也得不回来:

INSERT

但数据在那里:

pfams=# INSERT INTO person_details (first_name, family_name, town) VALUES ('Jim', 'Doe', 'Eders') RETURNING id;
 id
----

(1 row)

INSERT 0 1

我在这里缺少什么?

pfams=# SELECT * FROM person_details;
 id | first_name | family_name | street |  town
----+------------+-------------+--------+--------
  1 | John       | Doe         |        | Eders
  2 | Jim        | Doe         |        | Eders
(2 rows)

1 个答案:

答案 0 :(得分:1)

你太近了;)你只需要在触发器中更新NEW.id

CREATE FUNCTION t0ii_person_details() RETURNS trigger AS $$
DECLARE
  addr  integer;
BEGIN
  -- Want at least a town to insert anything into table address.
  IF (NEW.town IS NOT NULL) THEN
    INSERT INTO address(street, town)
      VALUES (NEW.street, NEW.town)
      RETURNING id INTO addr;
  ELSE
    addr := NULL;
  END IF;

  INSERT INTO person(first_name, family_name, address)
    VALUES (NEW.first_name, NEW.family_name, addr) 
    -- here is the only change I made
    RETURNING id INTO NEW.id;
  RETURN NEW;
END; $$ LANGUAGE plpgsql SECURITY DEFINER;