我在表col1
,col2
中有两列,它们都是唯一索引的(col1是唯一的,因此是col2)。
我需要插入此表,使用ON CONFLICT
语法并更新其他列,但我不能在conflict_target
子句中使用这两列。
有效:
INSERT INTO table
...
ON CONFLICT ( col1 )
DO UPDATE
SET
-- update needed columns here
但如何为多个列执行此操作,如下所示:
...
ON CONFLICT ( col1, col2 )
DO UPDATE
SET
....
答案 0 :(得分:42)
id
需要唯一索引*来执行冲突检测。因此,您只需要在两列上创建唯一索引:
valid_time
*除了唯一索引外,您还可以使用docs。这些比唯一约束更通用。假设您的表格包含valid_time
和tsrange
的列(并且id
是id
),并且您希望允许重复的id
,但不能重叠时间段。唯一约束不会对您有所帮助,但如果排除约束,您可以说如果valid_time
等于旧valid_time
并且其<video>
重叠,则排除新记录它的<video>
。&#34;
答案 1 :(得分:28)
CREATE TABLE dupes(col1 int primary key, col2 int, col3 text,
CONSTRAINT col2_unique UNIQUE (col2)
);
INSERT INTO dupes values(1,1,'a'),(2,2,'b');
INSERT INTO dupes values(3,2,'c')
ON CONFLICT (col1) DO UPDATE SET col3 = 'c', col2 = 2
我们称之为Q1。结果是
ERROR: duplicate key value violates unique constraint "col2_unique"
DETAIL: Key (col2)=(2) already exists.
conflict_target可以执行唯一索引推断。表演时 推理,它由一个或多个index_column_name列和/或组成 index_expression表达式和可选的index_predicate。所有 table_name唯一索引,不考虑顺序,包含 确切地推断出conflict_target指定的列/表达式 (选择)作为仲裁指标。如果指定了index_predicate,则为 作为推断的进一步要求,必须满足仲裁指标。
这给人的印象是以下查询应该有效,但它没有,因为它实际上需要col1和col2上的一个唯一索引。但是,这样的索引并不能保证col1和col2单独是唯一的,这是OP的要求之一。
INSERT INTO dupes values(3,2,'c')
ON CONFLICT (col1,col2) DO UPDATE SET col3 = 'c', col2 = 2
让我们调用此查询Q2(这会因语法错误而失败)
Postgresql的行为方式是因为在第二列上发生冲突时应该发生的事情没有很好地定义。有很多可能性。例如,在上面的Q1查询中,当col1
发生冲突时,postgresql应该更新col2
吗?但如果这会导致col1
上的另一场冲突呢? postgresql如何处理呢?
解决方案是将ON CONFLICT与old fashioned UPSERT结合起来。
CREATE OR REPLACE FUNCTION merge_db(key1 INT, key2 INT, data TEXT) RETURNS VOID AS
$$
BEGIN
LOOP
-- first try to update the key
UPDATE dupes SET col3 = data WHERE col1 = key1 and col2 = key2;
IF found THEN
RETURN;
END IF;
-- not there, so try to insert the key
-- if someone else inserts the same key concurrently, or key2
-- already exists in col2,
-- we could get a unique-key failure
BEGIN
INSERT INTO dupes VALUES (key1, key2, data) ON CONFLICT (col1) DO UPDATE SET col3 = data;
RETURN;
EXCEPTION WHEN unique_violation THEN
BEGIN
INSERT INTO dupes VALUES (key1, key2, data) ON CONFLICT (col2) DO UPDATE SET col3 = data;
RETURN;
EXCEPTION WHEN unique_violation THEN
-- Do nothing, and loop to try the UPDATE again.
END;
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
您需要修改此存储函数的逻辑,以便按照您希望的方式更新列。像
一样调用它SELECT merge_db(3,2,'c');
SELECT merge_db(1,2,'d');
答案 2 :(得分:4)
答案 3 :(得分:3)
OR / AND
答案 4 :(得分:2)
首先,您必须在列col1, col2
上创建表唯一约束。然后,一旦您这样做,您可以执行以下操作:
INSERT INTO dupes values(3,2,'c')
ON CONFLICT ON CONSTRAINT dupes_pkey
DO UPDATE SET col3 = 'c', col2 = 2
答案 5 :(得分:2)
如果您使用的是postgres 9.5,则可以使用EXCLUDED空格。
取自What's new in PostgreSQL 9.5:
的示例INSERT INTO user_logins (username, logins)
VALUES ('Naomi',1),('James',1)
ON CONFLICT (username)
DO UPDATE SET logins = user_logins.logins + EXCLUDED.logins;
答案 6 :(得分:0)
通常(我认为)可以生成仅包含一个on conflict
的语句,该语句指定与您要插入的内容相关的唯一约束。
通常,一次仅一个约束是“相关”约束。 (如果有很多,那么我想知道是否有些奇怪/设计怪异的东西,嗯。)
示例:
(许可证:不是 CC0,仅限CC-By)
// there're these unique constraints:
// unique (site_id, people_id, page_id)
// unique (site_id, people_id, pages_in_whole_site)
// unique (site_id, people_id, pages_in_category_id)
// and only *one* of page-id, category-id, whole-site-true/false
// can be specified. So only one constraint is "active", at a time.
val thingColumnName = thingColumnName(notfificationPreference)
val insertStatement = s"""
insert into page_notf_prefs (
site_id,
people_id,
notf_level,
page_id,
pages_in_whole_site,
pages_in_category_id)
values (?, ?, ?, ?, ?, ?)
-- There can be only one on-conflict clause.
on conflict (site_id, people_id, $thingColumnName) <—— look
do update set
notf_level = excluded.notf_level
"""
val values = List(
siteId.asAnyRef,
notfPref.peopleId.asAnyRef,
notfPref.notfLevel.toInt.asAnyRef,
// Only one of these is non-null:
notfPref.pageId.orNullVarchar,
if (notfPref.wholeSite) true.asAnyRef else NullBoolean,
notfPref.pagesInCategoryId.orNullInt)
runUpdateSingleRow(insertStatement, values)
并且:
private def thingColumnName(notfPref: PageNotfPref): String =
if (notfPref.pageId.isDefined)
"page_id"
else if (notfPref.pagesInCategoryId.isDefined)
"pages_in_category_id"
else if (notfPref.wholeSite)
"pages_in_whole_site"
else
die("TyE2ABK057")
on conflict
子句是动态生成的,具体取决于我要执行的操作。如果我要为页面插入通知首选项,那么在site_id, people_id, page_id
约束下可能会有唯一的冲突。而且,如果我正在为类别配置通知首选项,那么我知道可以违反的约束是site_id, people_id, category_id
。
因此,在您的情况下,我也很可能会生成正确的on conflict (... columns )
,因为我知道我想做的事,然后知道哪一个?众多独特约束中的一个就是可以被违反的约束。
答案 7 :(得分:0)
有点骇人听闻,但我通过将col1和col2中的两个值连接到新列col3(类似于两者的索引)中来进行解决,并与之进行了比较。仅当您需要它同时匹配col1和col2时才有效。
INSERT INTO table
...
ON CONFLICT ( col3 )
DO UPDATE
SET
-- update needed columns here
其中col3 = col1和col2中值的串联。
答案 8 :(得分:0)
ON CONFLICT是非常笨拙的解决方案,运行
UPDATE dupes SET key1=$1, key2=$2 where key3=$3
if rowcount > 0
INSERT dupes (key1, key2, key3) values ($1,$2,$3);
可在Oracle,Postgres和所有其他数据库上运行
答案 9 :(得分:0)
我知道我迟到了,但对于寻找答案的人,我发现了这个: here
INSERT INTO tbl_Employee
VALUES (6,'Noor')
ON CONFLICT (EmpID,EmpName)
DO NOTHING;
答案 10 :(得分:0)
ON CONFLICT ( col1, col2 )
DO UPDATE
SET
工作正常。但您不应更新 col1
, col2
在 SET
部分。