Tengo una columna dentro de una tabla que puede tomar uno de estos tres valores: 'past', 'present', 'future'
Sin embargo, solo una fila puede tener el valor 'presente'. Esto está siendo verificado por un índice de restricción único simple. Aún así, quiero que, cuando llegue el momento, alguien haga manualmente una fila 'futura' en la fila 'presente', para activar una función. Después de crear el activador e intentar probarlo actualizando manualmente una fila 'futura' a la fila 'presente', como era de esperar, recibí el siguiente error:
ERROR: duplicate key value violates unique constraint "semester_status_present" DETAIL: Key (semester_status)=(present) already exists.
Pensarlo por un minuto es completamente lógico, pero ¿qué puedo hacer en este caso? ¿Está el índice fuera de lugar?
esta es la restricción de índice:
CREATE UNIQUE INDEX semester_status_present ON public."Semester" USING btree (semester_status) WHERE semester_status = 'present'::semester_status;¡gracias de antemano!
¡EDITAR!: ¡El disparador convierte la fila actual anterior en una fila pasada también! Sin embargo, el desencadenante es after update on "Semester" , ya que evita el ciclo de actualización infinito
Utilice un activador anterior para que pueda cambiar la fila actual existente a una fila anterior antes de que la actualización intente crear una segunda fila actual y rompa la restricción.
Función de disparo.
create function swap_present() returns trigger as $$ begin update "Semester" set semester_status = 'past' where semester_status = 'present'::semester_status and id != new.id; return new; end; $$ language plpgsql;Puse una verificación en new.id allí para que el activador no cambie la fila que está cambiando. Reemplace esto con cualquiera que sea la identificación única en su tabla.
Definición de disparador.
create trigger semester_trigger before insert or update on "Semester" for each row when (new.semester_status = 'present'::semester_status) execute procedure swap_present(); La cláusula when significa que solo nos preocupamos si está cambiando o insertando una fila actual.
Dado que es un disparador posterior, el valor duplicado se produce cuando el futuro se convierte en la fila actual, pero antes de que la fila actual no se haya cambiado al pasado.
Intente cambiar su disparador a antes. Eso significaría que habría un momento en el tiempo en el que no hay fila 'presente' (el presente se cambia a pasado, el futuro aún no se ha cambiado a presente).
Espero que desee que esto se ejecute por declaración en lugar de por fila. Probablemente querrá agregar una condición para que solo se active cuando una fila futura se cambie a una fila actual. De esa forma, agregar nuevas filas futuras o cambiar las filas presentes/pasadas no aplicará el disparador.