如何在postgres中通过插入返回来防止重复插入?

Kar*_*ris 3 postgresql hibernate

我正在尝试为我的数据库创建一些规则以防止重复插入,但由于我们也处于休眠状态,因此 .save() 被称为 insert xxx RETURNING *

我似乎无法使插入规则在插入返回时很好地发挥作用。

CREATE TABLE test ( aaa int, bbb int);

insert into test VALUES(1, 2);

CREATE RULE "testRule1" AS ON INSERT TO  test
  WHERE EXISTS(SELECT 1 FROM test 
                WHERE (aaa, bbb)=(NEW.aaa, NEW.bbb))
  DO INSTEAD NOTHING;
Run Code Online (Sandbox Code Playgroud)

如果我尝试仅插入 1 个条件规则

insert into test VALUES(1, 2);
ERROR:  cannot perform INSERT RETURNING on relation "test"
HINT:  You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.

CREATE RULE "testRule2" AS ON INSERT TO  test
  DO INSTEAD INSERT INTO test VALUES(new.*)
  RETURNING test.*;
Run Code Online (Sandbox Code Playgroud)

如果我尝试同时插入条件和无条件规则

insert into test VALUES(1, 2);
ERROR:  infinite recursion detected in rules for relation "test"
Run Code Online (Sandbox Code Playgroud)

我的设置不可能实现这一点吗?

FXD*_*FXD 8

避免插入重复项的正确方法是将字段定义为UNIQUE(或PRIMARY KEY)

CREATE TABLE Test (
aaa integer,
bbb integer,
val text, /* The reason why I added this field is explained later */
UNIQUE (aaa,bbb)
)
Run Code Online (Sandbox Code Playgroud)

如果元组已经存在,插入将失败并显示错误代码(从数据库接收错误代码是一件好事,正如我最近在这里解释的那样)。

如果您无法接受错误,或者您想在一条记录中插入多条记录而insert不必关心哪一条违反UNIQUE约束,则正确的语法是使用该ON CONFLICT子句。

INSERT INTO Test values (1,1,'Some value')
ON CONFLICT DO NOTHING
Run Code Online (Sandbox Code Playgroud)

基本上将插入具有唯一元组的第一条记录。即使查询本身尝试插入重复项,也是兼容的,如下例所示:

INSERT INTO Test values (2,2,'Will be inserted'), (2,2,'Will not be inserted')
ON CONFLICT DO NOTHING
Run Code Online (Sandbox Code Playgroud)

RETURNING当然,这也允许您在同一查询中使用该子句。