我有8个类似的PL / pgSQL函数;它们在视图上用作INSTEAD OF INSERT/UPDATE/DELETE
触发器,使它们可写。每个视图组合了一个通用表的列(在下面的示例中称为"事物")和一个特殊的表(" shaped_things"和" flavored_things"在下面)。顺便说一句,PostgreSQL的继承功能不能在我们的案例中使用。
触发器必须在通用表中插入/更新行;这些部分在所有8个功能中是相同的。由于通用表有大约30列,我试图在那里使用辅助函数,但是我无法将视图的NEW
记录传递给需要{的things
记录的函数{1}}记录为输入。
(类似问题已被问及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...
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)"以上是我想要通过调用辅助函数来替换的。
我最初的尝试是取代声明"(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函数无法接受类型记录" 。
当函数被调用为things
时,赋予insert_thing(NEW)
类型的参数不起作用:&#34;函数insert_thing(flavored_view)不存在&#34; < / em>的
这里似乎没有简单的铸造; insert_thing(NEW::things)
生成&#34;无法将类型flavoured_view转换为&#34; 。为每个视图编写CAST函数将删除我们通过使用辅助函数获得的功能。
有什么想法吗?
答案 0 :(得分:9)
根据完整图片,有多种选择 基本上,您的插入功能可以这样工作:
CREATE FUNCTION insert_thing (_thing flavored_view)
RETURNS int AS
$func$
INSERT INTO things (name) VALUES ($1.name) -- plus 30 more columns
RETURNING id;
$func$ LANGUAGE sql;
使用视图的行类型,因为触发器中的NEW
属于此类型。
使用一个简单的SQL函数,它可以内联并可能表现得更好。
演示电话:
SELECT insert_thing('(1, foo, 1, bar)');
在触发器内flavored_trig ()
:
inserted_id := insert_thing(NEW);
或者,基本上改写了:
IF TG_OP = 'INSERT' THEN
INSERT INTO flavored_things(thing_id, flavor)
VALUES (insert_thing(NEW), NEW.flavor);
RETURN NEW;
ELSIF ...
不是PL / pgSQL之外的有效类型,它只是PL / pgSQL中未知行类型的通用占位符,因此您无法使用它用于函数声明中的输入参数。record
对于接受各种行类型的更具动态性的功能,您可以使用polymorphic type。例子:
答案 1 :(得分:1)
基本上,您可以将记录转换为hstore变量,并将hstore变量而不是记录变量传递给函数。您将记录转换为hstore,即:
DECLARE r record; h hstore;
h = hstore(r);
您的助手功能也应该改变:
CREATE FUNCTION insert_thing (new_thing hstore) 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;
电话:
inserted_id = insert_thing(hstore(NEW));
希望有所帮助
答案 2 :(得分:0)
复合类型。 PostgresSQL有关于此的文档,你基本上需要使用像
这样的东西'()'或ROW()构造要传递给函数的行的复合类型。