用于更新组合键中的列的SQL查询

时间:2017-05-30 08:11:31

标签: sql postgresql

我有一个包含3列的表

CREATE TABLE my_table (
  A_id INTEGER NOT NULL,
  B_id INTEGER NOT NULL,
  C CHARACTER VARYING(50) NOT NULL,
  PRIMARY KEY (A_id, B_id, C)
);

我必须使用其他值更新B_id列中的某些值。 我试过这个问题

UPDATE my_table
SET B_id = 10
WHERE B_id = 20

但问题是这给了我一个" 重复键值违反了唯一约束"

因为在某些地方,表格有这样的数据

A_id, B_id, C
1,     10,  a
1,     20,  a  ## this row seems to cause constraint problem
1,     20,  b
2,     20,  a
2,     20,  b 

我希望上面的数据看起来像这样

  A_id,  B_id,  C
    1,     10,  a
    1,     10,  b
    2,     10,  a
    2,     10,  b 

因此,一般情况下,如果已经存在组合键,则删除值为20的组合,否则更新该值。 在期待中感谢!

2 个答案:

答案 0 :(得分:2)

...如果密钥组合已经存在,则忽略...

如果忽略意味着:不要更新,那么您可以使用exists(tuple_with _new_values in the same table),如下所示:

UPDATE my_table mt
SET B_id = 10
WHERE mt.B_id = 20
AND NOT EXISTS ( SELECT *
        FROM my_table nx        -- same table
        WHERE nx.A_id = mt.A_id -- same value
        AND nx.B_id = 10        -- new value
        AND nx.C_id = mt.C_id   -- same value
        );

[更新]问题发生变化后。您可以使用CTE组合两个操作:

  • 首先:删除更新将与之冲突的记录
  • 秒:更新已删除的记录
WITH del AS ( -- delete tuples for which UPDATE would cause a conflict
        DELETE FROM my_table mt
        WHERE mt.B_id = 20
        AND EXISTS ( SELECT *
                FROM my_table nx
                WHERE nx.A_id = mt.A_id
                AND nx.B_id = 10
                AND nx.C_id = mt.C_id
                )
        RETURNING *
        )
UPDATE my_table upd -- UPDATE the records that were not deleted
SET B_id = 10
WHERE upd.B_id = 20
AND NOT EXISTS ( SELECT *
        FROM del
        WHERE del.A_id = upd.A_id
        AND del.B_id = upd.B_id
        AND del.C_id = upd.C_id
        );

答案 1 :(得分:0)

尝试像:

t=# with s as (select * from my_table where B_id = 10)
update my_table t
set B_id = 10
from s
WHERE t.B_id = 20
and s.A_id != t.A_id and s.c != t.c;

以上内容应该更新所有会产生异常的内容 然后删除20年代:

delete from my_table WHERE t.B_id = 20

当然至少要在交易中完成