我有两个表格foo
和bar
以及after trigger
foo
,它会更改bar
表格上的内容。
create table foo(id serial primary key, _key char(128) not null);
create table bar(id bigserial primary key, _key_p char(256) not null);
因此,当我有一个事务,例如调用下面的函数时,触发器在事务之后触发,而不是语句或相关的dml操作。
foo
表的触发器:
create or replace function foo_trg_func()returns trigger as $$
declare k_p char(256);begin
k_p:=(select res from prepare_pa(new.key));
insert into bar(_key_p) values(k_p);--insert it to the bar
end $$ language plpgsql;
--
create trigger foo_trg
after insert on foo
for each row execute procedure foo_trg_func();
样本函数/事务
create or replace function `bas`(int,character(128))returns int as $$
-- some commands
with res as (select res as "d" from c_key($1,$2)),
-- attemp to insert into foo and expect the insertion to bar too
ins as (insert into foo(_key) select d from res returning 1) --line[5]
-- check the effect of the foo_trg
select _key_p from bar,res where _key_p=res.d; --line[7]
$$ language sql
调用触发器并通过bar
触发器将数据插入foo
表,但在函数调用之后,我无法在第7行获得触发器插入的结果。
我现在该怎么办?
我还必须提到可以将触发器标记为相反或之前,但它会引起许多变化,所以我想知道它是否可以用{{1触发器。
答案 0 :(得分:0)
首先,您必须知道您正在运行单个语句(包含多个CTE。)
单个语句alls的公用表表达式与数据库的相同的基本快照相同。
每个CTE(或最终命令)都可以重用先前CTE(内部临时表)的输出,但对其他CTE的基础表的影响不可见。您的最终SELECT
无法看到您的CTE ins
对基础表格产生任何影响。
如果您之后在单独的语句中运行SELECT
(但仍在同一个事务中 - 可以在同一个函数中),您将看到效果。
此相关答案的详细信息:
现在您有两个相互矛盾的要求:
您希望将更改的行用于基础表(不能从CTE的RETURNING
子句中获得,因为这些是来自另一个表的触发器的副作用)。但是这些变化在同一声明中不可见。
您希望将其与CTE返回的值与RETURNING
子句相结合,但 在CTE语句之外不可见。
通过从TEMP TABLE中的CTE实现派生表来解决此问题:
CREATE OR REPLACE FUNCTION bas (int, text)
RETURNS SETOF int AS
$func$
BEGIN
CREATE TEMP TABLE foo_tmp (LIKE foo) ON COMMIT DROP;
WITH ins AS (
INSERT INTO foo(_key)
SELECT res FROM c_key($1,$2) f
RETURNING foo.*
)
INSERT INTO foo_tmp
SELECT * FROM ins;
RETURN QUERY
SELECT b._key_p
FROM bar b
JOIN foo_tmp f ON b._key_p = f._key;
END
$func$ LANGUAGE plpgsql;
或者,你可以删除触发器并手动执行INSERT
(如果这是一个单一的入口点)。
你几乎肯定不想要character(128)
。使用varchar(128)
,或varchar
或text
:
标识符(`res`
)没有反引号。这看起来像MySQL的溢出,在Postgres中是无稽之谈。 Use double-quotes instead(仅在必要时)。
您的触发功能可以更简单/更便宜:
CREATE OR REPLACE FUNCTION foo_trg_func()
RETURNS trigger AS
$func$
BEGIN
INSERT INTO bar(_key_p)
SELECT res FROM prepare_pa(NEW.key);
END
$func$ LANGUAGE plpgsql;
如果prepare_pa()
返回单个值,则更简单。