You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 14:42:27