Vistas
En resumen: Una vista es una consulta guardada bajo un nombre que se usa como una tabla, pero que no almacena datos propios.
Problema
El mismo cálculo en todas partes
¿Cuánto vale un pedido? En orders no hay ninguna suma. Se calcula a partir de las filas del pedido:
Este cálculo hace falta para el informe diario, para el extracto del cliente, para la lista de pedidos sin pagar. Cada vez se escribe de nuevo. Si algún día se añade un gasto de envío o un descuento, hay que arreglarlo en diez sitios. Y uno se olvidará.
La idea
CREATE VIEW
CREATE VIEW nombre AS SELECT … guarda una consulta bajo un nombre. Eso es una vista. Después la vista se lee como una tabla:
El cálculo se escribe una vez, en la vista. Los informes solo dicen FROM order_totals.
La idea
Como una tabla
En SELECT una vista se usa como cualquier tabla: con WHERE, ORDER BY, JOIN. En este campo order_totals ya está creada. Aquí están los pedidos nuevos, con el cliente y el valor:
La consulta es más corta y más clara: «el pedido, el cliente, el valor». Cómo se calcula el valor está escondido en la vista.
Pruébalo
Los pedidos grandes
La vista order_totals está lista. ¿Qué pedidos pasan de 100 €? Muestra el número y el valor.
Solución
SELECT order_id, total FROM order_totals WHERE total > 100;SELECT order_id, total FROM order_totals WHERE total > 100;. Tres pedidos: 13 (102,10 €), 23 (104 €) y 56 (118,20 €).
Míralo
Una vista no contiene datos
El cliente del pedido 1 llama: quiere 5 paquetes de queso blanco, no 4. Ejecuta la consulta y mira los dos resultados:
Antes son 31,60 €, después 39,50 €. Nadie tocó la vista. La vista no guarda los valores, solo la consulta. Cada lectura la ejecuta de nuevo sobre las tablas, así que una vista no puede quedar desactualizada.
Por eso tampoco se puede escribir en una vista:
Los datos se cambian en las tablas de las que lee la vista.
Más precisamente, para curiosos
PostgreSQL tiene también CREATE MATERIALIZED VIEW: una vista que guarda su resultado como una tabla. Se lee rápido, pero se desactualiza y se refresca con REFRESH MATERIALIZED VIEW. Se usa para informes pesados que no necesitan ser exactos al segundo. SQLite no tiene una vista así.
Pruébalo
Ventas por producto
Crea una vista product_sales: para cada producto (product_id), cuántas unidades se pidieron (sold), sin contar las filas de pedidos cancelados.
Solución
CREATE VIEW product_sales AS
SELECT oi.product_id, SUM(oi.quantity) AS sold
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
WHERE o.status <> 'cancelled'
GROUP BY oi.product_id;CREATE VIEW product_sales AS SELECT oi.product_id, SUM(oi.quantity) AS sold FROM order_items oi JOIN orders o ON o.id = oi.order_id WHERE o.status <> 'cancelled' GROUP BY oi.product_id;. Sin el JOIN con orders, el estado del pedido no se ve.
La idea
DROP VIEW
Una vista se quita con DROP VIEW. DROP TABLE no funciona:
Las tablas de las que lee la vista no se tocan. Solo quitas la consulta guardada.
Más precisamente, para curiosos
Para cambiar una vista en SQLite, la quitas con DROP VIEW y la creas de nuevo con CREATE VIEW. PostgreSQL y MySQL tienen CREATE OR REPLACE VIEW, y SQLite no:
También funciona al revés: una columna que usa una vista no se puede quitar con DROP COLUMN (la lección anterior lo mencionó).
Ejercicio
Dos informes
1. El dueño quiere enviar tarjetas de agradecimiento a los tres clientes que han pedido por más dinero.
Usando la vista order_totals, muestra el nombre del cliente y cuánto ha pedido en total (spent), sin contar los pedidos cancelados. Solo los tres primeros, de más a menos.
Solución
SELECT c.name, ROUND(SUM(t.total), 2) AS spent
FROM customers c
JOIN orders o ON o.customer_id = c.id
JOIN order_totals t ON t.order_id = o.id
WHERE o.status <> 'cancelled'
GROUP BY c.id, c.name
ORDER BY spent DESC
LIMIT 3;JOIN de customers, orders y order_totals, WHERE o.status <> 'cancelled', GROUP BY el cliente, ORDER BY spent DESC LIMIT 3. Maria Ivanova (375,70 €), Martin Kostov (216,80 €) y Nikolay Stoyanov (143,50 €).
2. Por la mañana el almacén mira qué pedidos están esperando.
Crea una vista open_orders con el número del pedido, el nombre del cliente y el valor del pedido, solo para los pedidos nuevos y pagados (new, paid). Usa order_totals.
Solución
CREATE VIEW open_orders AS
SELECT o.id, c.name, t.total
FROM orders o
JOIN customers c ON c.id = o.customer_id
JOIN order_totals t ON t.order_id = o.id
WHERE o.status IN ('new', 'paid');CREATE VIEW open_orders AS SELECT o.id, c.name, t.total FROM orders o JOIN customers c ON c.id = o.customer_id JOIN order_totals t ON t.order_id = o.id WHERE o.status IN ('new', 'paid');. 23 pedidos. Una vista puede leer de otra vista.
Test
Ponte a prueba
Lecciones relacionadas
Sección «Lecciones relacionadas»- Se basa en: INSERT: insertar filas · UPDATE: cambiar valores · CREATE TABLE: crear una tabla · ALTER TABLE: cambiar una tabla
- Continúa en: La panadería, etapa 5: la base trabaja sola · La panadería, etapa 6: el informe, la copia y DROP
- Ejercicios sobre el tema: Tablas y reglas