PostgreSQL-具有多个冲突的UPSERT

时间:2019-10-17 16:20:26

标签: postgresql unique-constraint upsert

摆弄SQL片刻之后,我无法达到预期的效果。 我搜索了PostgreSQL的文档,但是无法按照我想要的方式进行任何工作。

我有一个包含5列的表格:

| id | some_serial | user_id |  foo   |  bar   |
|----|-------------|---------|--------|--------|
|  1 |     8000000 |    42   |   AA   | <null> |
|  2 |     8000001 |  <null> | <null> |   CC   |

我想将新值插入到表中,返回相应的序列。 如果新值与 user_id foo bar 中的任何数据匹配,则我希望更新该行,再次在此返回相应的序列号。

期望的行为:

例如: 插入42, AA, BB将更新第一行。 bar将变成BB,并返回8000000。

| id | some_serial | user_id |  foo   |  bar   |
|----|-------------|---------|--------|--------|
|  1 |     8000000 |    42   |   AA   |   BB   |
|  2 |     8000001 |  <null> | <null> |   CC   |

插入43, null, CC将更新第二行。 user_id将变为43,并返回8000001。

| id | some_serial | user_id |  foo   |  bar   |
|----|-------------|---------|--------|--------|
|  1 |     8000000 |    42   |   AA   |   BB   |
|  2 |     8000001 |    43   | <null> |   CC   |

插入44, DD, EE将创建一个新行,并返回新序列号。

| id | some_serial | user_id |  foo   |  bar   |
|----|-------------|---------|--------|--------|
|  1 |     8000000 |    42   |   AA   |   BB   |
|  2 |     8000001 |    43   | <null> |   CC   |
|  3 |     8000002 |    44   |   DD   |   EE   |

实际行为:

我已经尝试对(user_id,foo,bar)进行了唯一的约束,但这并没有给我想要的行为。第一次插入后,结果将是:

| id | some_serial | user_id |  foo   |  bar   |
|----|-------------|---------|--------|--------|
|  1 |     8000000 |    42   |   AA   | <null> |
|  2 |     8000001 |  <null> | <null> |   CC   |
|  3 |     8000002 |    42   |   AA   |   BB   |

据我了解,这是因为约束将一起检查3列的唯一性。

我拥有的约束

 ALTER TABLE my_table
   ADD CONSTRAINT my_table_user_id_foo_bar_unique
UNIQUE (user_id, foo, bar);

我拥有的UPSERT:

INSERT INTO my_table (user_id, foo, bar)
VALUES (42, 'AA', 'BB')
    ON CONFLICT ON CONSTRAINT my_table_user_id_foo_bar_unique
    DO UPDATE
   SET user_id = 42,
       foo = COALESCE(my_table.foo, EXCLUDED.foo),
       bar = COALESCE(my_table.bar, EXCLUDED.bar)
RETURNING some_serial;

任何帮助将不胜感激。 :-)

与此同时,我的解决方案是

我首先尝试更新该行,如果存在则返回该行。

UPDATE my_table
   SET user_id = $1
     , foo = COALESCE(foo, $2)
     , bar = COALESCE(bar, $3)
 WHERE (foo = $2 AND foo <> NULL)
    OR (bar = $3 AND bar <> NULL)
RETURNING some_serial

如果该请求未返回任何内容,我将其插入:

INSERT INTO my_table (user_id, foo, bar)
VALUES ( $1, $2, $3)
RETURNING some_serial

0 个答案:

没有答案