UPSERT测试代码中的语法错误

时间:2016-02-14 15:06:10

标签: postgresql insert upsert postgresql-9.5 postgresql-json

我正在尝试使用以下测试代码测试新的PostgreSQL upsert syntax,但得到语法错误:

test=> CREATE TABLE test1 (
test(>         key1 integer PRIMARY KEY check (key1 > 0),
test(>         key2 integer check (key2 > 0)
test(> );
CREATE TABLE

test=> CREATE OR REPLACE FUNCTION upsert(IN in_json_array jsonb)
test->         RETURNS void AS
test-> $func$
test$>         UPDATE test1 t SET     
test$>         t.key1 = (obj->>'key1')::int,
test$>         t.key2 = (obj->>'key2')::int
test$>         FROM JSONB_ARRAY_ELEMENTS(in_json_array) obj
test$>         WHERE  t.key1 = obj->'key1'
test$>         ON CONFLICT DO UPDATE SET
test$>         key1 = excluded.key1,
test$>         key2 = excluded.key2;
test$> 
test$> $func$ LANGUAGE sql;

ERROR:  syntax error at or near "ON"
LINE 9:         ON CONFLICT DO UPDATE SET
                ^

上面的代码为什么会失败?

此外,test1表有几个约束(非负值和唯一主键)。如何仅解决唯一性约束?

更新2 :我已从UPDATE切换到INSERT(抱歉这个愚蠢的错误!),但我仍然在努力学习语法:

test=> CREATE OR REPLACE FUNCTION upsert(IN in_json_array jsonb)
test->         RETURNS void AS
test-> $func$
test$>         INSERT into test1 AS t (t.key1, t.key2)
test$>         VALUES ((obj->>'key1')::int, (obj->>'key2')::int)
test$>         FROM JSONB_ARRAY_ELEMENTS(in_json_array) obj
test$>         WHERE t.key1 = obj->'key1'
test$>         ON CONFLICT DO UPDATE SET
test$>         t.key1 = excluded.key1,
test$>         t.key2 = excluded.key2;
test$> $func$ LANGUAGE sql;

ERROR:  syntax error at or near "FROM"
LINE 6:         FROM JSONB_ARRAY_ELEMENTS(in_json_array) obj
                ^

我还尝试将JSON行更改为:

SELECT obj FROM JSONB_ARRAY_ELEMENTS(in_json_array)

但也失败了......

这是我方便的测试代码:

select upsert('[{"key1":1,"key2":2},{"key1":3,"key2":4}]'::jsonb);
select upsert('[{"key1":1,"key2":2},{"key1":1,"key2":4}]'::jsonb);

2 个答案:

答案 0 :(得分:4)

因为这是导致错误的Google最高结果:

ON CONFLICT DO UPDATE command cannot affect row a second time

我将补充一点,这可能是由重复冲突VALUES 引起的,例如

INSERT INTO distributors (did, dname)
VALUES 
    (5, 'Gizmo Transglobal'), 
    (5, 'Associated Computing, Inc')
ON CONFLICT (did) DO UPDATE SET dname = EXCLUDED.dname;

在这种情况下,我们尝试插入两个值dim设置为5的值。由于dim是索引,因此查询本身不会产生冲突。

我在实现微服务和处理请求时遇到了这个错误,其中一些请求有重复的记录。

答案 1 :(得分:1)

如果您使用的是from条款,则无法使用values。它是insert into .. values (..) insert into .. select ... from ...,但不是两者。

您也无法从提供插入的select子句中的插入引用目标表。我不确定你想要实现的目标。

您还需要确定哪些"冲突"应该通过指定应该处理的约束的PK列或名称来捕获。在你的情况下,它应该是pk列:

所有这些组合在一起,功能应如下所示:

CREATE OR REPLACE FUNCTION upsert(IN in_json_array jsonb)
        RETURNS void AS
$func$
    INSERT into test1 (key1, key2)
    select distinct on ((obj->>'key1')::int)
             (obj->>'key1')::int, 
             (obj->>'key2')::int
    FROM JSONB_ARRAY_ELEMENTS(in_json_array) obj
    ON CONFLICT (key1) DO 
      UPDATE SET key1 = excluded.key1,
                 key2 = excluded.key2;
$func$ 
LANGUAGE sql;

distinct on ()将确保select只返回key1的一个值,以避免" ON CONFLICT DO UPDATE命令不能再次影响行& #34;错误。请注意,如果选择中没有order by,它基本上是"随机"正在选择哪个键。如果您想选择特定的一个,则需要在order by

中添加select