Tengo una tabla con un índice único en dos campos, lane_id y position.
Ahora, quiero actualizar la fila usando esta consulta:
UPDATE "teams_ticket" SET "position" = ("teams_ticket"."position" + 1) WHERE ("teams_ticket"."lane_id" = 1 AND "teams_ticket"."position" >= 0)Que termina con:
duplicate key value violates unique constraint "teams_ticket_position_bfcce9fa_uniq"Si tengo más de un billete.
¿Cómo puedo solucionar este problema?
Necesita restricciones deferrable (y en realidad diferirlas, temporalmente). Aplazable significa que las restricciones no se comprueban inmediatamente (por ejemplo, cuando se reescribe la tupla índice), sino al final de la transacción (o declaración), cuando se han actualizado todas las filas:
-- \i tmp.sql
CREATE TABLE positions ( seq SERIAL PRIMARY KEY , position INTEGER NOT NULL UNIQUE DEFERRABLE ); INSERT INTO positions(position) SELECT generate_series(1,10) gs; BEGIN; SET CONSTRAINTS ALL DEFERRED; update positions SET position= position +1 WHERE seq <= 6 ; SELECT * FROM positions ; UPDATE positions SET position= position +1 WHERE seq > 6 ; SELECT * FROM positions ; UPDATE positions SET position= position +1 ; SELECT * FROM positions ; COMMIT;Puede usar el cursor para actualizarlos uno por uno.
DO $$ DECLARE r record; BEGIN FOR r IN SELECT lane_id, position FROM teams_ticket WHERE lane_id=1 AND position >= 0 ORDER BY position DESC LOOP UPDATE teams_ticket SET position=position+1 WHERE position=r.position AND lane_id=r.lane_id; END LOOP; END$$;Puedes probar
UPDATE teams_ticket t SET position = q.position + 1 FROM ( SELECT lane_id, position FROM teams_ticket WHERE lane_id = 1 AND position >= 0 ORDER BY lane_id, position DESC ) q WHERE t.lane_id = q.lane_id AND t.position = q.position