我有两个简单的表person
和address
,其中插入了一个可更新的视图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();
一个简单的插入:
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)
但是,如果我想直接从{{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)
答案 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;