Vistas en SQL
En esta lección
Una vista es una consulta a la que le pones nombre y guardas en la base de datos. A partir de ese momento puedes usarla como si fuera una tabla más: hacerle SELECT, filtrarla con WHERE o unirla con otras tablas. En esta lección aprenderás a crear vistas, a cambiarlas y borrarlas, y sobre todo a saber cuándo te conviene usarlas.
El problema: consultas que repites una y otra vez
Imagina que en la tienda del curso necesitas a menudo ver los pedidos con el nombre del cliente. Cada vez tienes que escribir el mismo JOIN:
SELECT p.id AS pedido_id, c.nombre AS cliente, c.ciudad, p.fecha, p.importe
FROM pedidos p
JOIN clientes c ON c.id = p.cliente_id;
Si esa consulta aparece en diez sitios de tu aplicación y un día cambia algo (por ejemplo, quieres añadir la edad), tendrás que tocar los diez. Además, un compañero que no conozca bien las tablas puede equivocarse al escribir el JOIN.
Una vista resuelve las dos cosas: escribes la consulta una vez, le das un nombre y todo el mundo usa ese nombre.
Crear una vista: CREATE VIEW
La sintaxis es CREATE VIEW nombre AS seguida de cualquier SELECT:
CREATE VIEW pedidos_con_cliente AS
SELECT p.id AS pedido_id,
c.nombre AS cliente,
c.ciudad,
p.fecha,
p.importe
FROM pedidos p
JOIN clientes c ON c.id = p.cliente_id;
Al ejecutarlo no se muestra ningún resultado: la base de datos solo guarda la definición. Ahora puedes consultarla igual que una tabla:
SELECT * FROM pedidos_con_cliente;
| pedido_id | cliente | ciudad | fecha | importe |
|---|---|---|---|---|
| 1 | Ana García | Santander | 2026-09-01 | 45.00 |
| 2 | Marta Ruiz | Santander | 2026-09-03 | 120.50 |
| 3 | Ana García | Santander | 2026-09-10 | 12.99 |
| 4 | Luis Pérez | Bilbao | 2026-09-12 | 60.00 |
| 5 | Eva Martín | Madrid | 2026-09-15 | 33.25 |
Los nombres de las columnas de la vista son los alias que pusiste en el SELECT (pedido_id, cliente). Por eso conviene poner alias claros: son la “cara” de la vista.
Usarla como una tabla
Todo lo que ya sabes de SELECT funciona sobre una vista:
SELECT cliente, importe
FROM pedidos_con_cliente
WHERE importe > 40
ORDER BY importe DESC;
| cliente | importe |
|---|---|
| Marta Ruiz | 120.50 |
| Luis Pérez | 60.00 |
| Ana García | 45.00 |
Fíjate en que la consulta ya no tiene ningún JOIN. Quien la escribe no necesita saber que los datos vienen de dos tablas.
Una vista no guarda datos
Esto es lo más importante que debes entender: una vista no es una copia de los datos. Es solo una consulta con nombre. Cada vez que la usas, la base de datos ejecuta el SELECT que hay dentro sobre las tablas reales.
Lo vas a ver con un ejemplo. Crea una vista con el número de pedidos y el total facturado por ciudad (usa GROUP BY):
CREATE VIEW total_por_ciudad AS
SELECT c.ciudad,
COUNT(p.id) AS num_pedidos,
SUM(p.importe) AS total
FROM clientes c
JOIN pedidos p ON p.cliente_id = c.id
GROUP BY c.ciudad;
SELECT * FROM total_por_ciudad ORDER BY total DESC;
| ciudad | num_pedidos | total |
|---|---|---|
| Santander | 3 | 178.49 |
| Bilbao | 1 | 60.00 |
| Madrid | 1 | 33.25 |
Ahora Pablo, de Madrid, hace su primer pedido:
INSERT INTO pedidos (id, cliente_id, fecha, importe)
VALUES (6, 4, '2026-09-20', 18.00);
SELECT * FROM total_por_ciudad ORDER BY total DESC;
| ciudad | num_pedidos | total |
|---|---|---|
| Santander | 3 | 178.49 |
| Bilbao | 1 | 60.00 |
| Madrid | 2 | 51.25 |
No has tenido que “actualizar” la vista: siempre muestra los datos al día, porque los calcula en el momento. La parte negativa es que una vista con una consulta pesada tarda lo mismo que esa consulta; no la hace más rápida.
Consejo: puedes unir una vista con tablas u otras vistas, filtrarla o agruparla. Para la base de datos es una tabla más a la hora de escribir consultas.
Para qué sirven las vistas
1. Simplificar consultas
Es el uso que has visto: esconder JOIN, cálculos y agrupaciones detrás de un nombre sencillo. El código de tu aplicación queda más corto y, si la lógica cambia, la cambias en un solo sitio.
2. Seguridad: enseñar solo una parte
Supón que el equipo de marketing necesita la lista de clientes, pero no debe ver su edad. Puedes crear una vista sin esa columna:
CREATE VIEW clientes_publicos AS
SELECT id, nombre, ciudad
FROM clientes;
| id | nombre | ciudad |
|---|---|---|
| 1 | Ana García | Santander |
| 2 | Luis Pérez | Bilbao |
| 3 | Marta Ruiz | Santander |
| 4 | Pablo Díaz | Madrid |
| 5 | Eva Martín | Madrid |
Después das permiso a esos usuarios sobre la vista, pero no sobre la tabla clientes. Lo verás en la lección de usuarios y permisos.
3. Informes
Las vistas con totales, medias y recuentos (como total_por_ciudad) son la base de muchos paneles e informes. Las herramientas de informes se conectan a la vista y no necesitan conocer la estructura interna.
4. Aislar la aplicación de cambios en las tablas
Si reorganizas las tablas (por ejemplo, divides una en dos), puedes crear una vista con el nombre y las columnas antiguas. El código viejo sigue funcionando mientras lo vas adaptando.
Cambiar y borrar vistas
Para modificar una vista existente, MySQL y PostgreSQL tienen CREATE OR REPLACE VIEW. Si la vista no existe, la crea; si existe, la sustituye:
CREATE OR REPLACE VIEW clientes_publicos AS
SELECT id, nombre, ciudad, edad >= 18 AS mayor_de_edad
FROM clientes;
Para borrarla se usa DROP VIEW. Con IF EXISTS no da error si no existe:
DROP VIEW IF EXISTS total_por_ciudad;
Borrar una vista no borra ningún dato: solo desaparece la consulta guardada. Las tablas clientes y pedidos siguen intactas.
Nota: SQLite no tiene
CREATE OR REPLACE VIEW. Tienes que hacerDROP VIEW IF EXISTSy luegoCREATE VIEWotra vez. En PostgreSQL,CREATE OR REPLACEsolo permite añadir columnas al final; si quieres quitar o renombrar columnas, también tienes que borrarla y crearla de nuevo. MySQL tiene ademásALTER VIEW nombre AS SELECT ..., que hace lo mismo queCREATE OR REPLACE.
Para ver qué vistas tienes y cómo están definidas, en MySQL:
SHOW FULL TABLES WHERE Table_type = 'VIEW';
SHOW CREATE VIEW pedidos_con_cliente;
Vistas actualizables
¿Se puede hacer INSERT, UPDATE o DELETE sobre una vista? En MySQL y PostgreSQL, sí, si la vista es sencilla. Por ejemplo:
CREATE VIEW clientes_santander AS
SELECT id, nombre, ciudad, edad
FROM clientes
WHERE ciudad = 'Santander';
UPDATE clientes_santander SET edad = 35 WHERE id = 1;
El cambio se aplica a la tabla clientes, porque la vista no tiene datos propios. Cada fila de la vista corresponde exactamente a una fila de la tabla, así que la base de datos sabe qué fila tocar.
Una vista no es actualizable cuando esa correspondencia se pierde. Las causas más habituales son:
| La vista contiene… | Por qué no se puede actualizar |
|---|---|
GROUP BY o funciones como SUM, COUNT | Una fila de la vista resume muchas filas de la tabla |
DISTINCT | Una fila puede venir de varias filas iguales |
UNION | Los datos vienen de varias consultas |
Columnas calculadas (importe * 1.21) | No puedes guardar un valor en un cálculo |
Subconsultas en el SELECT | La base de datos no sabe qué tabla modificar |
Por ejemplo, total_por_ciudad nunca será actualizable: ¿qué significaría cambiar el total de Madrid a 100?
Con vistas que tienen JOIN, MySQL permite a veces hacer UPDATE si solo tocas columnas de una de las tablas, pero no DELETE. Las reglas son complicadas y cambian entre sistemas. En la práctica, usa las vistas para leer y modifica los datos sobre las tablas.
Nota: en SQLite las vistas son siempre de solo lectura. Si intentas el
UPDATEanterior obtienes el errorcannot modify clientes_santander because it is a view.
WITH CHECK OPTION
Con la vista clientes_santander, nada te impide hacer esto en MySQL:
INSERT INTO clientes_santander (id, nombre, ciudad, edad)
VALUES (6, 'Sara López', 'Madrid', 31);
La fila se guarda en clientes, pero no aparece en la vista, porque no es de Santander. Es raro y confuso. Para impedirlo, añade WITH CHECK OPTION al final de la definición:
CREATE OR REPLACE VIEW clientes_santander AS
SELECT id, nombre, ciudad, edad
FROM clientes
WHERE ciudad = 'Santander'
WITH CHECK OPTION;
Ahora cualquier INSERT o UPDATE a través de la vista que deje una fila fuera del WHERE da error. Solo puedes añadir o cambiar clientes de Santander.
Vistas materializadas
A veces sí interesa guardar el resultado, por ejemplo en un informe que tarda un minuto en calcularse y que se consulta muchas veces al día. Para eso existen las vistas materializadas: guardan una copia de los datos en disco.
Nota: PostgreSQL las tiene con
CREATE MATERIALIZED VIEW informe AS SELECT .... Como son una copia, no se actualizan solas: tienes que ejecutarREFRESH MATERIALIZED VIEW informe;cuando quieras recalcularlas (por ejemplo, cada noche). MySQL y SQLite no tienen vistas materializadas; se suelen imitar con una tabla normal que se rellena periódicamente.
Errores frecuentes
- Pensar que la vista es una copia de los datos. Una vista normal siempre lee las tablas en el momento. Si la consulta es lenta, la vista también lo será.
- Columnas sin alias. Si pones
SUM(p.importe)sinAS total, la columna de la vista se llamará algo comoSUM(p.importe), incómodo de usar. Ponle siempre un alias. - Poner
ORDER BYdentro de la vista. Algunos sistemas lo ignoran y otros lo permiten, pero no garantiza el orden cuando la usas en otra consulta. Ordena en elSELECTque usa la vista. - Borrar o renombrar una tabla que usa una vista. La vista se queda “rota” y da error al consultarla. Antes de hacer ALTER TABLE o DROP, revisa qué vistas dependen de esa tabla.
- Vistas encima de vistas encima de vistas. Funciona, pero cuando algo va lento o falla es muy difícil encontrar el porqué. Mantén pocas capas.
- Nombres que se confunden con tablas. Muchos equipos usan un prefijo como
v_(v_pedidos_con_cliente) para saber a simple vista que es una vista.
Resumen
| Instrucción | Para qué sirve |
|---|---|
CREATE VIEW v AS SELECT ... | Guarda una consulta con nombre |
SELECT * FROM v | Usa la vista como una tabla |
CREATE OR REPLACE VIEW v AS ... | Crea o sustituye la vista (MySQL y PostgreSQL) |
ALTER VIEW v AS ... | Cambia la vista (MySQL) |
DROP VIEW IF EXISTS v | Borra la vista, no los datos |
WITH CHECK OPTION | Impide insertar o cambiar filas que la vista no mostraría |
CREATE MATERIALIZED VIEW | Guarda una copia del resultado (PostgreSQL) |
- Una vista es una consulta guardada, no una copia de los datos.
- Sirve para simplificar, proteger columnas o filas y preparar informes.
- Las vistas sencillas de una sola tabla se pueden actualizar en MySQL y PostgreSQL; las que tienen
GROUP BY,DISTINCTo cálculos, no. - En la siguiente lección verás cómo hacer que las consultas vayan más rápido con índices.
Pon a prueba lo que has aprendido
¿Te ha quedado claro? Márcala y verás tu progreso en el explorador.