UPSERT a row depending on the unique combination of values of two columns
本问题已经有最佳答案,请猛点这里访问。
我在数据库中有以下表格:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | CREATE TYPE STATUS AS ENUM ( 'void', 'steady', 'transition' ); CREATE TABLE relations ( marker INTEGER NOT NULL, related INTEGER[] NOT NULL, STATUS STATUS DEFAULT 'void'::STATUS NOT NULL, id serial -- pgAdmin requires primary key ); ALTER TABLE ONLY relations ADD CONSTRAINT pkey_id PRIMARY KEY (id); INSERT INTO relations (marker, related, STATUS) VALUES (3, '{6}', 'steady'::STATUS), (3, '{2}', 'transition'::STATUS), (6, '{4}', 'void'::STATUS), (6, '{2}', 'steady'::STATUS), (4, '{2}', 'steady'::STATUS), (4, '{6}', 'void'::STATUS); |
这就是表格的样子:
1 2 3 4 5 6 7 8 | marker | related | STATUS | id --------+---------+------------+---- 3 | {6} | steady | 1 3 | {2} | transition | 2 6 | {4} | void | 3 6 | {2} | steady | 4 4 | {2} | steady | 5 4 | {6} | void | 6 |
即使没有相应的约束,
我也有这个功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | CREATE OR REPLACE FUNCTION update_relations(INTEGER, INTEGER, STATUS) RETURNS void LANGUAGE plpgsql AS $_$ BEGIN UPDATE relations SET related = array_append(related, (CASE WHEN marker = $1 THEN $2 WHEN marker = $2 THEN $1 END) ) WHERE marker IN ($1,$2) AND STATUS = $3; END; $_$; |
我跑的时候
1 | SELECT update_relations(3, 4, 'void'::STATUS); |
然后我想要
1 2 3 4 5 6 7 8 | marker | related | STATUS | id --------+---------+------------+---- 3 | {6} | steady | 1 3 | {2} | transition | 2 6 | {4} | void | 3 6 | {2} | steady | 4 4 | {2} | steady | 5 4 | {6,3} | void | 6 |
如您所见,
1 2 3 4 5 6 7 8 9 | marker | related | STATUS | id --------+---------+------------+---- 3 | {6} | steady | 1 3 | {2} | transition | 2 6 | {4} | void | 3 6 | {2} | steady | 4 4 | {2} | steady | 5 4 | {6,3} | void | 6 3 | {4} | void | 7 |
如果不存在所需的
PS:我正在使用postgres 9.4。
Postgres"upsert"函数ON CONFLICT UPDATE为9.5或更高版本,但你的版本是9.4。
如果你不担心并发,你可以做到这一点:
1 2 3 4 5 6 7 8 9 | IF EXISTS (SELECT * FROM relations WHERE marker IN ($1,$2) AND STATUS = $3) THEN UPDATE relations SET ... WHERE marker IN ($1,$2) AND STATUS = $3; ELSE INSERT INTO relations (marker, related, STATUS) VALUES ($1, ARRAY[$2], $3); END IF |
这种方法确实存在并发问题。 有关更好(和更复杂)的解决方案,请参阅此问题。