Syntax error in UPSERT test code

两盒软妹~` 提交于 2019-12-12 10:23:11

问题


I am trying to test the new PostgreSQL upsert syntax with the following test code, but get the syntax error:

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
                ^

Why does the above code fail please?

Also, the test1 table has several constraints (non-negative values and the unique primary key). How to address the uniqueness constraint only?

UPDATE 2: I have switched from UPDATE to INSERT (sorry for the silly mistake!), but am still struggling with the syntax:

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
                ^

I have also tried to change the JSON-line to:

SELECT obj FROM JSONB_ARRAY_ELEMENTS(in_json_array)

but that fails too...

Here is my test code for your convenience:

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

回答1:


If you are using a from clause you can't use values. It's either insert into .. values (..) or insert into .. select ... from ... but not both.

You also can't reference the target table from the insert in the select clause that feeds the insert. I am not sure what you are trying to achieve with that.

You also need to qualify which "conflict" should be trapped by specifying the PK columns or the name of the constraint that should be handled. In your case it should be the pk column:

All that put together, the function should look like this:

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;

The distinct on () will make sure that only one value for key1 will be returned by the select to avoid the "ON CONFLICT DO UPDATE command cannot affect row a second time" error. Note that without an order by in the select it is basically "random" which key is being chosen. If you want to pick a specific one, you need to add an order by to the select




回答2:


As this is the top Google result for error:

ON CONFLICT DO UPDATE command cannot affect row a second time

I will add that It may be caused by a duplicate conflict VALUES, e.g.

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

In this case we try to insert two values with dim set to 5. As dim is the index it cannot have conflict in query itself.

I encountered this error when implementing microservice and processing requests, some of them having duplicate records.



来源:https://stackoverflow.com/questions/35393252/syntax-error-in-upsert-test-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!