PostgreSQL语法错误,出现在“ON”附近。

8
我创建了这个表格:
CREATE TABLE IF NOT EXISTS config_activity_log
(
  id                      serial primary key,
  activity_name           varchar(100) NOT NULL,
  last_config_version     varchar(50) NOT NULL,
  activity_status         varchar(100) NOT NULL DEFAULT 'Awaiting for cofman',
  cofman_last_update      bigint NOT NULL DEFAULT -1,
  is_error                boolean DEFAULT FALSE,
  activity_timestamp      timestamp DEFAULT current_timestamp
);

我尝试运行这个PostgreSQL脚本:

INSERT INTO config_activity_log
    (activity_name, last_config_version, activity_status)
VALUES
    ('test awating deployment','5837-2016-08-24_09-12-22', 'Awaiting for deployment')
ON CONFLICT (activity_name)
DO UPDATE SET
    activity_status = EXCLUDED.activity_status

为什么会出现语法错误?
psql:upsert_test_log.sql:7: ERROR:  syntax error at or near "ON"
LINE 5: ON CONFLICT (activity_name)

1
PSQL文档指出,如果在“ON CONFLICT”中使用括号,则括号内的内容是索引表达式。activity_name是一个索引表达式,还是仅仅是一个列?https://www.postgresql.org/docs/9.5/static/sql-insert.html - Neil Stockton
不,我已经添加了我的表创建脚本。activity_name没有索引,也不是唯一的。 - Elad Benda2
1
如果activity_name没有唯一约束,那么该字段就不会发生冲突(即如果没有约束,它会与什么冲突?)。通过在该列上添加唯一索引,冲突操作才有意义,因此应该可以正常工作。 - JohnLBevan
"on conflict" 在 Postgres 9.5 中被引入。您的 Postgres 版本是什么? - klin
请参阅 https://www.postgresql.org/docs/9.5/static/sql-insert.html#SQL-ON-CONFLICT 中的 conflict_target - JohnLBevan
显示剩余3条评论
2个回答

16

支持的版本

根据@klin在上面的评论中提到,ON CONFLICT仅从PostgreSQL 9.5开始支持。

如果您使用早期版本,则在此答案中有一些很好的信息:https://dev59.com/1mQm5IYBdhLWcg3w4CIN#17267423

唯一约束条件

activity_name上添加唯一索引。目前该列没有任何约束条件,因此该列不可能发生冲突。

CREATE UNIQUE INDEX UK_config_activity_log__activity_name 
ON config_activity_log (activity_name);

然而,如果您不想让该列成为唯一的,那么你预测会发生什么冲突或者你希望通过on conflict来解决什么问题?

请参见https://www.postgresql.org/docs/9.5/static/sql-insert.html#SQL-ON-CONFLICT中的conflict_target。


另一种语法是修改创建语句以在那里包含唯一条件; 例如:

CREATE TABLE IF NOT EXISTS config_activity_log
(
  id                      serial primary key,
  activity_name           varchar(100) NOT NULL UNIQUE,
  last_config_version     varchar(50) NOT NULL,
  activity_status         varchar(100) NOT NULL DEFAULT 'Awaiting for cofman',
  cofman_last_update      bigint NOT NULL DEFAULT -1,
  is_error                boolean DEFAULT FALSE,
  activity_timestamp      timestamp DEFAULT current_timestamp
);

所以也许我需要另一个解决方案。通常 activity_name 不是唯一的,但我想添加一个状态为“a”的“test”行。当它变成“b”时,我想将其更改为“a”,而不是添加新的测试行。 - Elad Benda2
如果我理解正确,那么意味着 activity_name 仍然是唯一的。也就是说,您有一行数据,其中 activity_name='test' 并且 activity_status='a'。您尝试插入第二行数据,其中 activity_name='test' 并且 activity_status='b',但在这种情况下,由于已经存在具有相同 activity_name 的行,您希望将其更新为 'b' 而不是创建新行;也就是说,数据库中始终只保留一个 activity_name='test' 的行。 - JohnLBevan

2
根据错误代码,您的版本不支持ON CONFLICT。在PostgreSQL 9.6上,错误信息为 -
[Code: 0, SQL State: 42P10]  ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification

1
所以也许我需要另一个解决方案。通常活动名称不是唯一的,但我想添加一个状态为“a”的“测试”行。当它变成“b”时,我希望将其改为“a”,而不是添加新的测试行。 - Elad Benda2
@EladBenda2,这不太清楚。你能否在你的问题中添加一个示例场景? - David דודו Markovitz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接