Estoy en camino de explorar disparadores y quiero crear uno que se dispare después de un evento de actualización en una columna game_saved en el juego. Como he leído en los documentos de PostgreSQL , es posible crear disparadores para columnas. La columna contiene valores boolean para que el usuario pueda agregar juegos a su colección o eliminarlos. Entonces, quiero que la función de activación calcule la cantidad de juegos establecidos en VERDADERO en la columna game_saved para un determinado usuario. Y luego actualice total_game_count en una tabla de colección de game_collection .
game_collection
id - BIGSERIAL primary key user_id - INTEGER REFERENCES users(id) total_game_count - INTEGER game_info
id - BIGSERIAL primary key user_id - INTEGER REFERENCES users(id) game_id - INTEGER REFERENCES games(id) review - TEXT game_saved - BOOLEANAquí está mi disparador (que no funciona y quiero averiguar por qué):
CREATE OR REPLACE FUNCTION total_games() RETURNS TRIGGER AS $$ BEGIN UPDATE game_collection SET total_game_count = (SELECT COUNT(CASE WHEN game_saved THEN 1 END) FROM game_info WHERE game_collection.user_id = game_info.user_id) WHERE user_id = NEW.user_id; RETURN NEW; END; $$ LANGUAGE plpgsql; CREATE TRIGGER tr_total_games AFTER UPDATE OF game_saved FOR EACH ROW EXECUTE PROCEDURE total_games(); Si cambio AFTER UPDATE OF game_saved (columna) a AFTER UPDATE ON game_info (tabla), el activador funciona correctamente. Entonces, hay un problema con la creación de un disparador específicamente para una actualización de columna.
¿Es una buena idea activar el disparador en la actualización de la columna o debo buscar otro enfoque aquí?
La sintaxis sería:
CREATE TRIGGER tr_total_games AFTER UPDATE OF game_saved ON game_info FOR EACH ROW EXECUTE PROCEDURE total_games();(Como se documenta en el manual).
Pero todo el enfoque es dudoso. Mantener los agregados actualizados a través del disparador es propenso a errores bajo una carga de escritura simultánea.
Y sin carga de escritura concurrente, hay soluciones más simples: simplemente sume/reste 1 del total actual...
Una VIEW sería una alternativa confiable. Elimine la columna game_collection.total_game_count por completo, y tal vez toda la tabla game_collection , que no parece tener ningún otro propósito. Cree una VIEW en su lugar:
CREATE VIEW v_game_collection AS SELECT user_id, count(*) AS total_game_count FROM game_info WHERE game_saved GROUP BY user_id; Esto devuelve a todos los usuarios con al menos 1 fila en game_info donde game_saved IS TRUE (y omite todos los demás).
Para tablas muy grandes, es posible que desee una MATERIALIZED VIEW o soluciones relacionadas para mejorar el rendimiento de lectura.