对于 PL/pgSQL 函数,请使用特殊变量FOUND:
CREATE FUNCTION foo(int, text)
RETURNS void
LANGUAGE plpgsql AS
$func$
BEGIN
INSERT INTO table1 (id, value)
VALUES ($1, $2)
ON CONFLICT DO NOTHING;
IF NOT FOUND THEN
INSERT INTO table2 (table1_id, value)
VALUES ($1, $2);
UPDATE table3
SET (table1_id, time)
= ($1 , now())
WHERE ???; -- you don't want to update all rows in table3?
END IF;
END
$func$;
Call:
SELECT foo(1, 'a');
FOUND
被设定为false
if the INSERT
实际上并没有插入任何行。
该手册关于ON CONFLICT Clause:
ON CONFLICT DO NOTHING
只是避免插入一行作为其
替代行动。
该手册关于获取结果状态
UPDATE
, INSERT
, and DELETE
语句集FOUND
如果至少有一个则为 true
行受到影响,如果没有行受到影响,则为 false。
需要明确的是,如果其中一行,则运行后面的语句table1
does已经存在,因此不会插入新行。 (就像您所要求的,但与您的问题标题相反。)
如果你只是想check是否存在行:
比赛条件?
如果同一事务中的后续命令depend上(尚未解锁)existing row in table1
(例如,使用 FK),您需要锁定它以防止并发事务同时删除或更新它。一种方法是:代替DO NOTHING
use DO UPDATE
,但是做not实际上更新该行。该行仍然被锁定:
INSERT INTO table1 AS t (id, value)
VALUES ($1, $2)
ON CONFLICT (id) DO UPDATE -- specify unique column(s) or constraint / index
SET id = t.id WHERE false; -- never executed, but locks the row
显然,如果您可以排除可能以冲突方式写入同一行的并发事务,那么问题就不存在。
详细解释:
- 如何在 RETURNING from INSERT ... ON CONFLICT 中包含排除的行
- 函数中的 SELECT 或 INSERT 是否容易出现竞争条件?