Tablas de eventos de solo anexado
Registre lo sucedido sin sobrescribir nunca los datos.
Tablas de eventos de solo anexado es una lección gratuita de SQL Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de SQL Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de SQL Academy incluye 4 lecciones en total.
¿Qué es una tabla de solo inserción?
Una tabla de eventos de solo inserción es una tabla en la que las filas únicamente se insertan, nunca se actualizan ni se eliminan. Cada fila representa algo que ocurrió en un momento específico.
Este patrón es la base de event sourcing. En lugar de almacenar el estado actual, se guarda cada cambio como un evento inmutable, lo que proporciona un historial completo y auditable.
Creación de una tabla de eventos
Una tabla de eventos bien diseñada registra quién hizo qué sobre qué recurso y cuándo. La columna occurred_at registra la marca de tiempo exacta, y DEFAULT NOW() garantiza que siempre se complete automáticamente.
Observe que en este diseño no hay ningún UPDATE ni DELETE: las filas son permanentes una vez escritas.
CREATE TABLE account_events (
id BIGSERIAL PRIMARY KEY,
account_id BIGINT NOT NULL,
event_type TEXT NOT NULL,
payload JSONB,
occurred_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);Inserción de eventos
Cada acción de un usuario —iniciar sesión, depositar dinero o cambiar una dirección de correo electrónico— se convierte en una fila nueva. Nunca se vuelve atrás para editar un evento anterior. Si es necesario corregir algo, se inserta un evento compensatorio.
Así se conserva la secuencia completa de lo ocurrido, en orden.
INSERT INTO account_events (account_id, event_type, payload)
VALUES
(42, 'account_opened', '{"plan": "free"}'),
(42, 'email_verified', '{"email": "alice@example.com"}'),
(42, 'plan_upgraded', '{"from": "free", "to": "pro"}');Lectura del historial completo
Como cada cambio de estado se almacena como una fila, consultar el historial completo de una cuenta consiste simplemente en ejecutar un SELECT ordenado por tiempo. Puede reproducir toda la trayectoria de un registro, desde el primer evento hasta el más reciente.
SELECT
id,
event_type,
payload,
occurred_at
FROM account_events
WHERE account_id = 42
ORDER BY occurred_at ASC;Obtención del estado actual
Con una tabla de solo inserción no se almacena directamente el estado actual: se obtiene leyendo el evento relevante más reciente. Aquí, el plan actual de la cuenta 42 es el que indique el evento plan_upgraded o account_opened más reciente.
El uso de ORDER BY occurred_at DESC LIMIT 1 permite obtener de forma eficiente la instantánea más reciente.
SELECT payload->>'to' AS current_plan
FROM account_events
WHERE account_id = 42
AND event_type IN ('account_opened', 'plan_upgraded')
ORDER BY occurred_at DESC
LIMIT 1;Aplicación de la inmutabilidad mediante reglas
La garantía de solo inserción puede aplicarse en el nivel de la base de datos mediante una RULE que ignore silenciosamente cualquier UPDATE o DELETE en la tabla. Esto evita mutaciones accidentales de cualquier aplicación que tenga acceso de escritura.
Un trigger que genere una excepción es una alternativa aún más estricta, ya que rechaza activamente la operación y muestra un error.
CREATE RULE no_update_events AS
ON UPDATE TO account_events
DO INSTEAD NOTHING;
CREATE RULE no_delete_events AS
ON DELETE TO account_events
DO INSTEAD NOTHING;Inmutabilidad mediante un trigger
Un trigger que genere una excepción es más estricto que una regla silenciosa: la aplicación recibe un error inmediatamente si intenta modificar un evento pasado. De este modo, los errores quedan visibles en lugar de ignorarse silenciosamente.
CREATE OR REPLACE FUNCTION deny_event_mutation()
RETURNS TRIGGER AS $$
BEGIN
RAISE EXCEPTION 'Event table is append-only: % is not allowed', TG_OP;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_deny_event_mutation
BEFORE UPDATE OR DELETE ON account_events
FOR EACH ROW EXECUTE FUNCTION deny_event_mutation();Conteo de eventos a lo largo del tiempo
Las tablas de solo inserción facilitan los análisis basados en el tiempo. Como cada evento tiene una marca de tiempo, puede agruparlos por día, semana o mes sin necesidad de columnas adicionales. El ejemplo siguiente cuenta cuántos eventos de cada tipo ocurrieron por día.
SELECT
DATE_TRUNC('day', occurred_at) AS day,
event_type,
COUNT(*) AS total
FROM account_events
GROUP BY 1, 2
ORDER BY 1, 2;Reconstrucción en un momento dado
Una de las propiedades más potentes de un registro de eventos es la posibilidad de reconstruir el estado de cualquier registro tal como existía en un momento pasado. Solo tiene que filtrar los eventos hasta la marca de tiempo deseada; no se necesita ninguna extensión de viaje en el tiempo.
Esto resulta invaluable para la depuración, las auditorías y el cumplimiento normativo.
-- What plan was account 42 on at the end of last month?
SELECT payload->>'to' AS plan_at_snapshot
FROM account_events
WHERE account_id = 42
AND event_type IN ('account_opened', 'plan_upgraded')
AND occurred_at <= DATE_TRUNC('month', NOW()) - INTERVAL '1 second'
ORDER BY occurred_at DESC
LIMIT 1;Eventos compensatorios en lugar de correcciones
Cuando se descubre un error —por ejemplo, un cargo incorrecto—, no se elimina el evento erróneo. En su lugar, se inserta un evento compensatorio que lo cancela o revierte. Ambos eventos permanecen visibles en el registro, mostrando exactamente qué ocurrió y cuándo se realizó la corrección.
Así se mantiene un rastro de auditoría completo y resistente a manipulaciones.
-- A charge was applied by mistake; record a reversal
INSERT INTO account_events (account_id, event_type, payload)
VALUES (
42,
'charge_reversed',
'{"reason": "billing_error", "reverses_event_id": 17}'
);Particionamiento de tablas de eventos grandes
Las tablas de eventos crecen rápidamente. Particionarlas por un intervalo de tiempo mantiene pequeñas las particiones individuales, acelera las consultas por rango y permite archivar o eliminar las particiones antiguas sin tocar los datos recientes.
El particionamiento declarativo de PostgreSQL facilita esta tarea: defina una partición RANGE sobre occurred_at y deje que la base de datos dirija las inserciones automáticamente.
CREATE TABLE account_events_2025
PARTITION OF account_events
FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
CREATE TABLE account_events_2026
PARTITION OF account_events
FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');Comprobación de conocimientos sobre tablas de solo inserción
Compruebe sus conocimientos sobre el diseño de tablas de eventos de solo inserción.
Repaso: tablas de eventos de solo inserción
En esta lección ha aprendido a diseñar y utilizar tablas de eventos de solo inserción:
- Inmutabilidad: las filas se insertan una sola vez y nunca se modifican. Los eventos pasados son hechos.
- Historial completo: se conserva cada cambio de estado, lo que permite disponer de rastros de auditoría completos y realizar consultas de un momento dado.
- Eventos compensatorios: los errores se corrigen añadiendo un nuevo evento de reversión, no eliminando el anterior.
- Aplicación: las reglas o los triggers en el nivel de la base de datos evitan mutaciones accidentales.
- Escalabilidad: el particionamiento por rangos mantiene el rendimiento de los registros de eventos grandes a lo largo del tiempo.
Las tablas de solo inserción son la columna vertebral de event sourcing, las arquitecturas CQRS y cualquier sistema en el que la auditabilidad y la precisión histórica sean fundamentales.
Preguntas frecuentes
¿La lección «Tablas de eventos de solo anexado» es gratis?
Sí — el texto completo de «Tablas de eventos de solo anexado» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de SQL Academy, actualiza a CoddyKit PRO. El curso de SQL Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Tablas de eventos de solo anexado»?
Registre lo sucedido sin sobrescribir nunca los datos. Practicas SQL Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar SQL Academy?
No se requiere experiencia previa. SQL Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Tablas de eventos de solo anexado»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de SQL Academy?
Sí. Cada lección de SQL Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Por qué conservar el historial
- Tablas de eventos de solo anexado
- Filas temporales y versionadas
- Reconstrucción del estado a partir de eventos