
SQL: Vistas (Views) para Abstraer y Asegurar tus Datos
- Dacadev
- Programación
- 23 de junio de 2026
Tabla de Contenido
Cuando una base de datos crece, las consultas empiezan a acumular lógica de negocio, joins repetidos, filtros de seguridad y columnas calculadas. En ese punto, las vistas en SQL se vuelven una herramienta clave: con CREATE VIEW podemos encapsular una consulta y exponerla como si fuera una tabla lógica. En el artículo anterior vimos subqueries y subconsultas; ahora vamos a usar ese mismo nivel de composición para abstraer, asegurar y simplificar el acceso a datos.
Note
En este artículo analizaremos qué es una vista, cómo crearla con CREATE VIEW, por qué ayuda con seguridad, agregación, complejidad y datos distribuidos, y qué condiciones debe cumplir una vista para ser actualizable.
Qué es una vista
Una vista no es una tabla física. En términos prácticos, es una consulta guardada en la base de datos que puedes consultar con SELECT como si fuera una tabla. La vista no almacena los registros por sí misma; almacena la definición del query que se ejecutará cuando accedas a ella.
Esto reduce repetición y mejora la legibilidad. Si una consulta se usa todos los días, o si quieres exponer solo ciertas columnas a un equipo o aplicación, una vista ofrece una interfaz estable sobre las tablas base.
Consideremos una vista sobre la tabla customer:
CREATE VIEW customer_vw
(customer_id,
first_name,
last_name,
email
)
AS
SELECT
customer_id,
first_name,
last_name,
concat(substr(email,1,2), '*****', substr(email, -4)) email
FROM customer;
En este ejemplo, la vista customer_vw expone customer_id, first_name, last_name y email. Observemos un detalle importante: el email no se entrega completo, sino enmascarado mediante concat() y substr().
Para usar la vista, la consultamos como cualquier otra relación:
mysql> SELECT first_name, last_name, email
-> FROM customer_vw;
+-------------+--------------+-------------+
| first_name | last_name | email |
+-------------+--------------+-------------+
| MARY | SMITH | MA*****.org |
| PATRICIA | JOHNSON | PA*****.org |
| LINDA | WILLIAMS | LI*****.org |
| BARBARA | JONES | BA*****.org |
| ELIZABETH | BROWN | EL*****.org |
...
| ENRIQUE | FORSYTHE | EN*****.org |
| FREDDIE | DUGGAN | FR*****.org |
| WADE | DELVALLE | WA*****.org |
| AUSTIN | CINTRON | AU*****.org |
+-------------+--------------+-------------+
599 rows in set (0.00 sec)
La consulta queda más expresiva: en lugar de repetir el cálculo del email en cada reporte, centralizamos esa lógica en una vista.
Si necesitas inspeccionar la estructura de una vista, puedes usar DESCRIBE o su forma corta DESC:
mysql> describe customer_vw;
+-------------+----------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------------------+------+-----+---------+-------+
| customer_id | smallint(5) unsigned | NO | | 0 | |
| first_name | varchar(45) | NO | | NULL | |
| last_name | varchar(45) | NO | | NULL | |
| email | varchar(11) | YES | | NULL | |
+-------------+----------------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
Tip
Puedes usar en vistas gran parte de lo que ya conoces de SQL: WHERE, ORDER BY, GROUP BY, funciones, expresiones calculadas e incluso JOIN. La vista encapsula la consulta; no elimina la necesidad de diseñarla correctamente.
Por qué usar vistas
Las vistas son útiles cuando necesitas definir una capa de acceso estable entre las tablas reales y los consumidores de datos. Esa capa puede servir para seguridad, reporting, simplificación de consultas o unificación de datos.
Seguridad de los datos
Cuando los usuarios consultan directamente las tablas base, pueden quedar expuestas columnas sensibles que no deberían estar disponibles para todos los perfiles. Una vista permite publicar solo las columnas necesarias y, si hace falta, transformar datos antes de mostrarlos.
El ejemplo de customer_vw aplica este patrón: el email se expone enmascarado. En una aplicación interna, podrías conceder permisos sobre la vista y evitar permisos directos sobre customer. Así reduces superficie de exposición sin duplicar datos.
Este enfoque también estabiliza contratos. Si la tabla base contiene más columnas en el futuro, los consumidores de la vista no las reciben automáticamente.
Agregar datos
Las vistas también funcionan bien para reportes o consultas agregadas. Si un equipo necesita revisar ventas por categoría de película, no tiene que escribir todos los JOIN cada vez.
CREATE VIEW sales_by_film_category
AS
SELECT
c.name AS category,
SUM(p.amount) AS total_sales
FROM payment AS p
INNER JOIN rental AS r ON p.rental_id = r.rental_id
INNER JOIN inventory AS i ON r.inventory_id = i.inventory_id
INNER JOIN film AS f ON i.film_id = f.film_id
INNER JOIN film_category AS fc ON f.film_id = fc.film_id
INNER JOIN category AS c ON fc.category_id = c.category_id
GROUP BY c.name
ORDER BY total_sales DESC;
Esta vista encapsula una agregación de pagos por categoría. El consumidor puede ejecutar SELECT * FROM sales_by_film_category; y enfocarse en el resultado, no en la mecánica de las relaciones.
Info
Una vista con agregaciones no materializa necesariamente el resultado. En muchos motores, la consulta se evalúa al leer la vista. Si el reporte es costoso y se consulta con alta frecuencia, analiza índices, planes de ejecución o alternativas como vistas materializadas cuando tu motor las soporte.
Esconder complejidad
Otra ventaja importante es ocultar consultas complejas detrás de un nombre claro. Analicemos una vista que resume estadísticas de películas usando subconsultas:
CREATE VIEW film_stats
AS
SELECT f.film_id, f.title, f.description, f.rating,
(SELECT c.name
FROM category c
INNER JOIN film_category fc
ON c.category_id = fc.category_id
WHERE fc.film_id = f.film_id) category_name,
(SELECT count(*)
FROM film_actor fa
WHERE fa.film_id = f.film_id
) num_actors,
(SELECT count(*)
FROM inventory i
WHERE i.film_id = f.film_id
) inventory_cnt,
(SELECT count(*)
FROM inventory i
INNER JOIN rental r
ON i.inventory_id = r.inventory_id
WHERE i.film_id = f.film_id
) num_rentals
FROM film f;
Esta consulta mezcla columnas directas, subqueries correlacionadas y conteos derivados. Usar film_stats como interfaz simplifica el consumo y reduce errores de copia al reutilizar la lógica.
También mejora la comunicación técnica. Un nombre como film_stats expresa intención de negocio mejor que una consulta extensa pegada en múltiples servicios, dashboards o scripts.
Datos distribuidos o particionados
Las vistas pueden ayudar a unificar datos que viven en diferentes tablas. Si una tabla está particionada por año, por región o por tipo de entidad, una vista puede presentar una estructura más simple para quien consulta.
El objetivo no es ocultar decisiones arquitectónicas críticas, sino evitar que cada consumidor tenga que conocer todos los detalles físicos del modelo. Una vista puede funcionar como una API interna de lectura dentro de la base de datos.
Vistas actualizables
Hasta ahora hemos usado vistas para leer datos. Sin embargo, algunos motores permiten ejecutar UPDATE, INSERT o DELETE a través de una vista, siempre que la base de datos pueda mapear la operación de forma inequívoca hacia las tablas base.
No todas las vistas son actualizables. Mientras más transformación tenga una vista, más difícil será determinar qué fila y qué columna real debe modificarse.
Para que una vista sea actualizable, considera estas restricciones típicas:
- No se usan funciones de agregación como
max(),min(),avg(),sum()o similares. - La vista no utiliza cláusulas
GROUP BYniHAVING. - No existen subconsultas en el
SELECTni en elFROM; y las subconsultas en elWHERE, si existen, no hacen referencia a tablas delFROM. - La vista no utiliza
UNION,UNION ALLniDISTINCT. - La cláusula
FROMincluye al menos una tabla o una vista actualizable. - Si hay más de una tabla o vista en el
FROM, se usan únicamenteINNER JOIN.
Warning
Las reglas exactas dependen del motor de base de datos. MySQL, PostgreSQL, SQL Server y Oracle tienen diferencias en sintaxis, permisos y casos soportados. Antes de depender de escrituras sobre vistas en producción, valida el comportamiento en tu motor específico.
Actualizando vistas simples
Supongamos nuevamente la vista customer_vw:
CREATE VIEW customer_vw
(customer_id,
first_name,
last_name,
email
)
AS
SELECT
customer_id,
first_name,
last_name,
concat(substr(email,1,2), '*****', substr(email, -4)) email
FROM customer;
Podemos actualizar una columna directa de la tabla base, como last_name, usando la vista:
mysql> UPDATE customer_vw
-> SET last_name = 'SMITH-ALLEN'
-> WHERE customer_id = 1;
Query OK, 1 row affected (0.11 sec)
Rows matched: 1 Changed: 1 Warnings: 0
La operación funciona porque last_name corresponde directamente a una columna actualizable de customer. La vista actúa como una capa de acceso, pero el motor sabe qué valor modificar.
En cambio, si intentamos actualizar email, la operación falla:
mysql> UPDATE customer_vw
-> SET email = 'MARY.SMITH-ALLEN@sakilacustomer.org'
-> WHERE customer_id = 1;
ERROR 1348 (HY000): Column 'email' is not updatable
La razón es que email en la vista no es la columna original; es una expresión calculada con concat() y substr(). El motor no puede inferir cómo convertir el valor nuevo en una actualización válida de la columna base.
También debes tener cuidado con INSERT. Insertar a través de una vista falla cuando la vista no expone todas las columnas NOT NULL de la tabla base, por lo que el INSERT no puede proporcionar valores para ellas. Si esas columnas no tienen DEFAULT, el motor no tiene forma segura de completar la fila.
Conclusión
Las vistas en SQL son una herramienta de diseño para crear interfaces de datos más limpias. Con CREATE VIEW puedes encapsular consultas repetidas, proteger columnas sensibles, construir reportes agregados y esconder complejidad sin duplicar información.
También es importante reconocer sus límites. Una vista no reemplaza un buen diseño de índices, no siempre mejora rendimiento y no siempre permite escritura. Cuando una vista incluye agregaciones, expresiones calculadas, DISTINCT, UNION o subconsultas complejas, normalmente debes tratarla como una interfaz de lectura.
Como siguiente paso de la serie, analizaremos cómo proteger la consistencia y el rendimiento de operaciones más críticas con transacciones, índices y constraints.


