PostgreSQL 9.4.24:如何实现存在则返回c1、不存在则插入数据的逻辑
实现PostgreSQL 9.4.24下的插入或返回逻辑
针对你提出的需求——当表tb中存在c2值的记录时返回对应c1,不存在则插入指定数据——由于PostgreSQL 9.4还没有引入9.5才有的ON CONFLICT语法,我们需要用兼容9.4的方案来实现。
首先有个前提:必须给tb表的c2字段添加唯一约束(或唯一索引),这样才能准确判断重复,同时避免并发场景下插入重复数据:
CREATE TABLE tb ( c1 INT, c2 INT UNIQUE -- 唯一约束是实现逻辑的核心 );
方案一:PL/pgSQL函数(推荐,处理并发更稳妥)
用PL/pgSQL写一个封装函数,既能处理逻辑判断,还能捕获并发插入时的唯一约束异常,保证结果正确:
CREATE OR REPLACE FUNCTION insert_or_return_c1(p_c1 INT, p_c2 INT) RETURNS INT AS $$ DECLARE existing_c1 INT; BEGIN -- 先检查是否存在目标c2的记录 SELECT c1 INTO existing_c1 FROM tb WHERE c2 = p_c2; -- 如果存在,直接返回对应的c1 IF existing_c1 IS NOT NULL THEN RETURN existing_c1; END IF; -- 不存在则尝试插入数据 BEGIN INSERT INTO tb (c1, c2) VALUES (p_c1, p_c2); RETURN p_c1; -- 返回插入的c1值 EXCEPTION WHEN UNIQUE_VIOLATION THEN -- 并发场景下,可能在我们检查后有其他进程插入了相同c2,此时捕获异常并再次查询 SELECT c1 INTO existing_c1 FROM tb WHERE c2 = p_c2; RETURN existing_c1; END; END; $$ LANGUAGE plpgsql;
使用方式
直接调用函数传入参数即可:
-- 第一次执行:表中无c2=200的记录,插入数据并返回100 SELECT insert_or_return_c1(100, 200); -- 第二次执行:表中已有c2=200的记录,返回已存在的c1值100 SELECT insert_or_return_c1(200, 200);
方案二:WITH语句实现(简洁但需处理并发异常)
如果你不想写函数,也可以用WITH子句结合SELECT和INSERT来实现,逻辑更直观,但并发场景下可能抛出唯一约束异常,需要调用方处理重试:
WITH existing AS ( -- 查询是否存在目标c2的记录 SELECT c1 FROM tb WHERE c2 = :p_c2 -- 替换:p_c2为实际要传入的c2值 ), inserted AS ( -- 仅当不存在时插入数据,并返回插入的c1 INSERT INTO tb (c1, c2) SELECT :p_c1, :p_c2 -- 替换:p_c1为实际要传入的c1值 WHERE NOT EXISTS (SELECT 1 FROM existing) RETURNING c1 ) -- 合并结果:存在则返回existing的c1,不存在则返回inserted的c1 SELECT c1 FROM existing UNION ALL SELECT c1 FROM inserted;
注意事项
如果多个请求同时执行这个语句,可能会有一个请求插入成功,另一个触发UNIQUE_VIOLATION错误。这种情况下,调用方需要捕获异常并重新执行查询,就能拿到已存在的c1值。
内容的提问来源于stack exchange,提问作者sahil mathew
相关产品推荐
相关产品推荐

