Estructura · valores derivados

Columnas generadas en SQL: GENERATED ALWAYS AS

Define un valor derivado dentro del esquema para que la base lo calcule a partir de otras columnas de la misma fila.

Lectura: 8–10 minDDL comprobadoComparativa por motor
Contenido de esta guía

Respuesta rápida

Una columna generada calcula su valor a partir de una expresión definida en el esquema. El usuario escribe las columnas base y el motor deriva la columna calculada cuando corresponde.

Ejemplo conceptual
subtotal REAL
  GENERATED ALWAYS AS (cantidad * precio_unitario) STORED

No es un DEFAULT: un valor predeterminado se usa cuando falta un valor en la inserción; una columna generada depende de una expresión y se vuelve a derivar cuando cambian las columnas de las que depende.

Modelo mental: dato base → expresión → dato derivado

Si cantidad = 2 y precio_unitario = 24.90, el subtotal puede derivarse de ambos valores. Guardar también un subtotal editable introduce el riesgo de que deje de coincidir con sus componentes. Una columna generada expresa esa dependencia en el esquema.

Pregunta de diseño: ¿el valor tiene vida propia o siempre debe ser el resultado de otras columnas de la misma fila? Si siempre es derivado y el motor lo permite, una columna generada puede ser una opción.

Ejemplo comprobado en SQLite

DDL + datos
CREATE TEMP TABLE lineas_generadas (
  id INTEGER PRIMARY KEY,
  cantidad INTEGER NOT NULL,
  precio_unitario REAL NOT NULL,
  subtotal REAL
    GENERATED ALWAYS AS (cantidad * precio_unitario) STORED
);

INSERT INTO lineas_generadas (id, cantidad, precio_unitario)
VALUES (1, 2, 24.90),
       (2, 3, 49.50);

SELECT id, cantidad, precio_unitario,
       ROUND(subtotal, 2) AS subtotal
FROM lineas_generadas
ORDER BY id;
Resultado comprobado
idcantidadprecio_unitariosubtotal
1224,9049,80
2349,50148,50

El INSERT no proporciona subtotal. La expresión de la columna lo calcula a partir de los datos base.

Si cambia la base, cambia el valor derivado

UPDATE comprobado
UPDATE lineas_generadas
SET cantidad = 4
WHERE id = 1;

SELECT id, cantidad, ROUND(subtotal, 2) AS subtotal
FROM lineas_generadas
WHERE id = 1;
Resultado después del UPDATE
idcantidadsubtotal
1499,60

El subtotal deja de ser 49,80 y pasa a 99,60 porque depende de cantidad. No necesitas mantener dos valores manualmente.

Columna generada vs DEFAULT, VIEW y cálculo en SELECT

Herramientas para valores derivados
OpciónDónde vive la lógicaCuándo encaja
Columna generadaEn la definición de la tablaEl valor debe derivarse siempre de la fila
DEFAULTEn la tabla, solo al faltar el valorNecesitas un valor inicial, no una fórmula permanente
VIEWEn una consulta reutilizableEl cálculo pertenece a una vista lógica más amplia
Expresión en SELECTEn una consulta concretaEl cálculo solo se necesita en ese resultado

La sintaxis no es idéntica entre motores

PostgreSQL, MySQL y SQLite usan el concepto de generated column y sintaxis basada en una expresión AS (...), con opciones de almacenamiento que dependen del motor. SQL Server denomina la característica computed column y permite PERSISTED para almacenar físicamente ciertos resultados calculados.

Terminología orientativa
MotorNombre / forma habitual
PostgreSQLGENERATED ALWAYS AS (...) STORED | VIRTUAL
MySQLcolumna generada AS (...), virtual o almacenada
SQLiteGENERATED ALWAYS AS (...), VIRTUAL o STORED
SQL Servercolumna AS expresion, opcionalmente PERSISTED

Las expresiones permitidas, indexación, nulabilidad, restricciones y operaciones de ALTER TABLE no coinciden exactamente. Diseña con la documentación del motor objetivo.

Errores frecuentes

Intentar insertar manualmente el valor derivado

La finalidad de la columna es que el motor determine el resultado a partir de su expresión. Inserta o modifica las columnas base, no mantengas una segunda copia manual.

Usar una columna generada para lógica que necesita otras filas

Estas expresiones se diseñan alrededor de los valores de la propia fila y están sujetas a restricciones del motor. Para agregados, subconsultas o lógica más amplia quizá necesites una consulta, vista u otra estrategia.

Asumir que STORED, VIRTUAL y PERSISTED significan exactamente lo mismo

Describen decisiones relacionadas con cálculo y almacenamiento, pero pertenecen a implementaciones distintas. No copies DDL de un motor a otro sin revisar sintaxis y limitaciones.

Práctica guiada

Intermedia · diseño de tabla

Calcula el área de cada rectángulo

Crea una tabla temporal rectangulos con ancho, alto y una columna generada almacenada area calculada como ancho * alto. Inserta (3, 4) y (2.5, 8).

Criterio de éxito: las áreas son 12 y 20.

Compatibilidad

La característica existe en los motores principales, pero con diferencias relevantes. PostgreSQL documenta columnas generadas almacenadas y virtuales; MySQL distingue generadas virtuales y almacenadas; SQLite también ofrece VIRTUAL/STORED; SQL Server utiliza columnas calculadas y la opción PERSISTED. Comprueba restricciones e indexación antes de migrar DDL.

Qué debes recordar

  • Una columna generada expresa una dependencia entre columnas de la misma fila.
  • No es equivalente a DEFAULT.
  • El motor recalcula el valor cuando cambian las columnas de las que depende.
  • La sintaxis y las restricciones cambian entre PostgreSQL, MySQL, SQLite y SQL Server.
  • Úsala cuando el valor sea realmente derivado; no para duplicar datos sin necesidad.

Conceptos relacionados

Fuentes técnicas consultadas