加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

postgresql – 对postgres upsert的部分更新违反了约束

发布时间:2020-12-13 15:51:52 所属栏目:百科 来源:网络整理
导读:我希望能够在postgres(9.5)中部分地进行upsert,但是当不满足所有约束时(例如not null约束),似乎部分upsert失败了 以下是方案和错误的示例 CREATE TABLE jobs ( id integer PRIMARY KEY,employee_name TEXT NOT NULL,address TEXT NOT NULL,phone_number TEXT
我希望能够在postgres(9.5)中部分地进行upsert,但是当不满足所有约束时(例如not null约束),似乎部分upsert失败了

以下是方案和错误的示例

CREATE TABLE jobs (
    id integer PRIMARY KEY,employee_name TEXT NOT NULL,address TEXT NOT NULL,phone_number TEXT
);

CREATE OR REPLACE FUNCTION upsert_job(job JSONB)
RETURNS VOID AS $$
BEGIN
INSERT INTO jobs AS origin VALUES(
    (job->>'id')::INTEGER,job->>'employee_name'::TEXT,job->>'address'::TEXT,job->>'phone_number'::TEXT
) ON CONFLICT (id) DO UPDATE SET
    employee_name = COALESCE(EXCLUDED.employee_name,origin.employee_name),address = COALESCE(EXCLUDED.address,origin.address),phone_number = COALESCE(EXCLUDED.phone_number,origin.phone_number);
END;
$$LANGUAGE PLPGSQL SECURITY DEFINER;


--Full insert (OK)
SELECT upsert_job('{"id" : 1,"employee_name" : "AAA","address" : "City,x street no.y","phone_number" : "123456789"}'::jsonb);

--Partial update that fulfills constraint (Ok)
SELECT upsert_job('{"id" : 1,"employee_name" : "BBB",x street no.y"}'::jsonb);

--Partial update that doesn't fulfill constraint (FAILS)
SELECT upsert_job('{"id" : 1,"phone_number" : "12345"}'::jsonb);

--ERROR:  null value in column "employee_name" violates not-null constraint
--DETAIL:  Failing row contains (1,null,12345).

我该如何解决这个问题呢?

解决方法

再想一想,如果id还没有存在怎么办?你不能只插入一个电话号码,因为它没有名字/地址,但这正是你告诉它要做的.因此约束变得疯狂并且失败,因为upsert尝试先插入然后在插入失败时更新.但是你的插入没有通过约束检查以查看它是否已经存在.

如果你想要部分,你可以做的是告诉它如何处理违反约束的部分.像这样的东西(这是不完整的,不处理所有部分数据场景):

CREATE OR REPLACE FUNCTION upsert_job(job JSONB)
RETURNS VOID AS $$
BEGIN
IF (job->>'phone_number' IS NOT NULL 
    AND job->>'employee_name' IS NOT NULL 
    AND job->>'address' IS NOT NULL) THEN
    INSERT INTO jobs AS origin VALUES(
        (job->>'id')::INTEGER,job->>'phone_number'::TEXT
    ) ON CONFLICT (id) DO UPDATE SET
        employee_name = COALESCE(EXCLUDED.employee_name,origin.phone_number);
ELSIF (job->>'phone_number' IS NOT NULL AND (job->>'employee_name' IS NULL AND job->>'address' IS NULL)) THEN
    UPDATE jobs SET phone_number=job->>'phone_number'::TEXT
    WHERE id=(job->>'id')::INTEGER;
END IF;

END;
$$LANGUAGE PLPGSQL SECURITY DEFINER;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读