UPSERT 测试代码中的语法错误
Syntax error in UPSERT test code
我正在尝试使用以下测试代码测试新的 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
table 有几个约束条件(非负值和唯一主键)。如何仅解决唯一性约束?
更新 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);
如果您使用的是 from
子句,则不能使用 values
。它是 insert into .. values (..)
或 insert into .. select ... from ...
但不是两者。
您也不能从提供插入内容的 select
子句中的插入内容引用目标 table。我不确定你想用它实现什么。
您还需要通过指定 PK 列或应处理的约束的 名称 来限定应捕获哪些 "conflict"。在您的情况下,它应该是 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 命令不能第二次影响行”错误。请注意,如果 select 中没有 order by
,则基本上 "random" 选择的是哪个键。如果你想选择一个特定的,你需要在 select
中添加一个 order by
因为这是错误的前 Google 结果:
ON CONFLICT DO UPDATE command cannot affect row a second time
我会补充说,这可能是由重复冲突值引起的,例如
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
是索引,因此查询本身不能有冲突。
我在实现微服务和处理请求时遇到了这个错误,有些请求有重复的记录。
我正在尝试使用以下测试代码测试新的 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
table 有几个约束条件(非负值和唯一主键)。如何仅解决唯一性约束?
更新 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);
如果您使用的是 from
子句,则不能使用 values
。它是 insert into .. values (..)
或 insert into .. select ... from ...
但不是两者。
您也不能从提供插入内容的 select
子句中的插入内容引用目标 table。我不确定你想用它实现什么。
您还需要通过指定 PK 列或应处理的约束的 名称 来限定应捕获哪些 "conflict"。在您的情况下,它应该是 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 命令不能第二次影响行”错误。请注意,如果 select 中没有 order by
,则基本上 "random" 选择的是哪个键。如果你想选择一个特定的,你需要在 select
order by
因为这是错误的前 Google 结果:
ON CONFLICT DO UPDATE command cannot affect row a second time
我会补充说,这可能是由重复冲突值引起的,例如
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
是索引,因此查询本身不能有冲突。
我在实现微服务和处理请求时遇到了这个错误,有些请求有重复的记录。