【发布时间】:2017-09-28 10:54:44
【问题描述】:
我有 8 个类似的 PL/pgSQL 函数;它们被用作视图上的INSTEAD OF INSERT/UPDATE/DELETE 触发器以使它们可写。每个视图都组合了一个通用表(在下面的示例中称为“事物”)和一个特殊表(下面的“shape_things”和“flavored_things”)的列。顺便说一下,PostgreSQL 的继承特性不能在我们的例子中使用。
触发器必须在通用表中插入/更新行;这些部分在所有 8 个功能中都是相同的。由于通用表有大约 30 列,我正在尝试在那里使用辅助函数,但我无法将视图的 NEW 记录传递给需要 things 记录作为输入的函数。
(here 和 here 提出了类似的问题,但我认为我无法在我的案例中应用建议的解决方案。)
简化架构
CREATE TABLE things (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
-- (plus 30 more columns)
);
CREATE TABLE flavored_things (
thing_id INT PRIMARY KEY REFERENCES things (id) ON DELETE CASCADE,
flavor TEXT NOT NULL
);
CREATE TABLE shaped_things (
thing_id INT PRIMARY KEY REFERENCES things (id) ON DELETE CASCADE,
shape TEXT NOT NULL
);
-- etc...
flavored_things 的可写视图实现
CREATE VIEW flavored_view AS
SELECT t.*,
f.*
FROM things t
JOIN flavored_things f ON f.thing_id = t.id;
CREATE FUNCTION flavored_trig () RETURNS TRIGGER AS $fun$
DECLARE
inserted_id INT;
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO things VALUES ( -- (A)
DEFAULT,
NEW.name
-- (plus 30 more columns)
) RETURNING id INTO inserted_id;
INSERT INTO flavored_things VALUES (
inserted_id,
NEW.flavor
);
RETURN NEW;
ELSIF TG_OP = 'UPDATE' THEN
UPDATE things SET -- (B)
name = NEW.name
-- (plus 30 more columns)
WHERE id = OLD.id;
UPDATE flavored_things SET
flavor = NEW.flavor
WHERE thing_id = OLD.id;
RETURN NEW;
ELSIF TG_OP = 'DELETE' THEN
DELETE FROM flavored_things WHERE thing_id = OLD.id;
DELETE FROM things WHERE id = OLD.id;
RETURN OLD;
END IF;
END;
$fun$ LANGUAGE plpgsql;
CREATE TRIGGER write_flavored
INSTEAD OF INSERT OR UPDATE OR DELETE ON flavored_view
FOR EACH ROW EXECUTE PROCEDURE flavored_trig();
上面标记为“(A)”和“(B)”的语句是我想用对辅助函数的调用来替换的。
INSERT 的辅助函数
我最初的尝试是将语句“(A)”替换为
inserted_id = insert_thing(NEW);
使用此功能
CREATE FUNCTION insert_thing (new_thing RECORD) RETURNS INTEGER AS $fun$
DECLARE
inserted_id INT;
BEGIN
INSERT INTO things (name) VALUES (
new_thing.name
-- (plus 30 more columns)
) RETURNING id INTO inserted_id;
RETURN inserted_id;
END;
$fun$ LANGUAGE plpgsql;
这会失败并显示错误消息“PL/pgSQL 函数不能接受类型记录”。
当函数被称为insert_thing(NEW) 时,给参数类型things 不起作用:“function insert_thing(flavored_view) 不存在”。
这里似乎没有简单的转换; insert_thing(NEW::things) 产生“无法将类型 flavored_view 转换为事物”。为每个视图编写一个 CAST 函数会消除我们通过使用辅助函数获得的东西。
有什么想法吗?
【问题讨论】:
-
首先,有各种优雅的解决方案。您要插入/更新
thing的所有 列还是仅更新选定的列?你的 Postgres 版本是什么?你的目标是什么?只是让它发挥作用?使用单一功能?优化性能?您是否必须处理可能的独特违规/竞争条件?
标签: postgresql function parameters triggers plpgsql