INSERT: añadir filas
El lenguaje DML (Data Manipulation Language) se encarga de escribir y modificar datos. Su primera pieza es INSERT, que añade una o varias filas nuevas a una tabla.
1.1 · Sintaxis completa
INSERT INTO platos (nombre, categoria, precio, stock)
VALUES ('Tortilla española', 'Entrantes', 9.75, 18);
En la lista de columnas decides qué campos llenas; los que no estén usarán su valor por
defecto (DEFAULT) o NULL.
id es AUTO_INCREMENT: MySQL le asigna el siguiente
número solo. No hace falta indicarla cuando insertas.1.2 · Varias filas a la vez
Puedes insertar muchos registros en una sola sentencia separando los valores con comas. Es mucho más rápido que lanzar un INSERT por fila:
INSERT INTO reservas (cliente, personas, fecha, hora, telefono)
VALUES
('Álvaro Peña', 2, '2026-09-20', '21:00:00', '677888999'),
('Marta Ruiz', 8, '2026-09-21', '20:30:00', NULL);
1.3 · Orden de los valores
Los valores deben coincidir en orden y tipo con la lista de columnas. Los textos van
entre comillas simples, los números no, las fechas entre comillas en formato
'AAAA-MM-DD' y las horas en 'HH:MM:SS':
INSERT INTO platos VALUES ('X', ...) sin lista de columnas funciona, pero es
frágil: si mañana cambia el orden de las columnas, tus datos se guardan mal. Indica siempre
las columnas.UPDATE: modificar filas
UPDATE cambia los valores de una o varias filas existentes. Su estructura tiene dos
partes: los nuevos valores con SET y el filtro con
WHERE.
2.1 · Sintaxis básica
UPDATE platos
SET precio = 8.50
WHERE id = 4;
Puedes cambiar varias columnas en un solo UPDATE separándolas con comas, y usar el valor anterior en la fórmula:
UPDATE platos
SET precio = precio * 1.10
WHERE categoria = 'Carnes';
2.2 · Actualizar a NULL
Para «limpiar» un dato puedes asignarle SET columna = NULL:
UPDATE reservas
SET telefono = NULL
WHERE cliente = 'Juan Rivas';
WHERE categoria = 'Bebidas' AND stock < 10. El UPDATE y el SELECT filtran igual.DELETE: eliminar filas
DELETE borra filas de una tabla. Al igual que UPDATE, necesita un WHERE
preciso; sin él… se vacía la tabla.
3.1 · Sintaxis básica
DELETE FROM reservas
WHERE id = 3;
DELETE FROM platos
WHERE activo = 0;
DELETE FROM platos; sin WHERE borra todas las filas
(la tabla queda vacía, pero existe). El orden de escritura importa: primero piensa qué quieres borrar, luego
escribe el WHERE, y al final revisas antes de ejecutar.3.2 · DELETE vs TRUNCATE
START TRANSACTION +
ROLLBACK puedes deshacer un DELETE por accidente. Lo verás en el bloque 6.Funciones de texto, número y fecha
Las funciones reciben un valor y devuelven otro transformado o calculado. Se usan dentro del
SELECT y son la base para presentar datos bien formateados.
4.1 · Funciones de texto
SELECT nombre,
UPPER(nombre) AS en_mayusculas,
CONCAT(UPPER(nombre), ' - ', categoria) AS etiqueta
FROM platos;
| Función | Qué hace | Ejemplo |
|---|---|---|
UPPER(x) / LOWER(x) | Mayúsculas / minúsculas | UPPER('paella') → 'PAELLA' |
CONCAT(a, b, c) | Une textos | CONCAT(nombre, ' (', categoria, ')') |
SUBSTRING(x, n, l) | Trozo desde n con longitud l | SUBSTRING('Entrecot', 1, 4) → 'Entr' |
LENGTH(x) | Número de caracteres | LENGTH('Tiramisú') → 8 |
REPLACE(x, a, b) | Cambia a por b | REPLACE(nombre, ' de ', ' con ') |
4.2 · Funciones numéricas
ROUND redondea, CEIL sube al entero siguiente y FLOOR baja al
anterior:
SELECT nombre,
precio,
ROUND(precio * 1.21, 2) AS precio_con_iva,
CEIL(precio) AS redondeo_arriba
FROM platos;
ROUND(valor, 2) — el segundo argumento indica cuántos decimales dejar.
Sin él, redondea al entero más cercano.4.3 · Funciones de fecha
SELECT cliente,
fecha,
CURDATE() AS hoy,
DATEDIFF(fecha, CURDATE()) AS dias_restantes
FROM reservas;
| Función | Qué devuelve |
|---|---|
CURDATE() / NOW() | Fecha de hoy / fecha y hora actuales |
DATEDIFF(a, b) | Días entre a y b |
DAYOFWEEK(f) | 1=Domingo … 7=Sábado (útil para reservas) |
DATE_FORMAT(f, '%d/%m/%Y') | Fecha con el formato que quieras |
CASE WHEN: lógica condicional
CASE WHEN añade condiciones «si… entonces… si no…» dentro de una consulta. Es el if/else de SQL y se usa para clasificar datos en el propio SELECT.
5.1 · CASE buscado
SELECT nombre,
precio,
CASE
WHEN precio < 8 THEN 'Económico'
WHEN precio <= 16 THEN 'Normal'
ELSE 'Premium'
END AS gama
FROM platos;
Las condiciones se evalúan en orden y se usa la primera que se cumpla. El ELSE
es opcional pero recomendado; si una fila no cumple nada y no hay ELSE, devuelve NULL.
precio <= 20, ningún plato llegaría
a ser 'Premium'. Las condiciones se miran de arriba a abajo.5.2 · CASE simple
Cuando comparas la misma columna con varios valores, existe la forma corta:
SELECT nombre,
categoria,
CASE categoria
WHEN 'Arroces' THEN 'Cocina de fuego'
WHEN 'Carnes' THEN 'Parrilla'
ELSE 'Otras'
END AS tipo_cocina
FROM platos;
5.3 · CASE en agregaciones
Es muy potente contar con condiciones: cuentas solo las filas que cumplen el WHEN (las otras son NULL y
COUNT no las cuenta):
SELECT categoria,
COUNT(*) AS total_platos,
SUM(CASE WHEN precio >= 15 THEN 1 ELSE 0 END) AS caros
FROM platos
GROUP BY categoria;
CASE termina con END (no con un ; interior). Es un
error típico olvidar el END. Dale siempre un alias con AS.✍️ Los 15 ejercicios del bloque
Abre MySQL Workbench, conecta y ejecuta sobre la base tw_restaurante. Esta vez no solo leerás:
insertarás, modificarás y borrarás. Escribe las palabras clave en mayúsculas y añade un
comentario -- con el número del ejercicio.
mysql -u root -p < sql/sql-bloque2_restaurante.sql.Sección A · INSERT
1 Un plato a la carta
Inserta el plato 'Tortilla de patatas' de categoría 'Entrantes',
precio 9.50 y stock 14 en la tabla platos. Indica las
columnas explícitamente.
Ver solución
-- Ejercicio 1: un plato nuevo
INSERT INTO platos (nombre, categoria, precio, stock)
VALUES ('Tortilla de patatas', 'Entrantes', 9.50, 14);
2 Dos platos a la vez
Con un único INSERT, inserte las bebidas 'Refresco de cola' (3.00, stock 40) y 'Agua mineral' (1.50, stock 60), ambas de categoría 'Bebidas'.
Ver solución
-- Ejercicio 2: dos bebidas nuevas de golpe
INSERT INTO platos (nombre, categoria, precio, stock)
VALUES
('Refresco de cola', 'Bebidas', 3.00, 40),
('Agua mineral', 'Bebidas', 1.50, 60);
3 Reserva sin teléfono
Inserta la reserva del cliente 'Nuria Campos' para 4 personas el '2026-09-22' a las '20:00:00'. Deja el teléfono sin dar valor (quedará NULL).
Ver solución
-- Ejercicio 3: reserva sin teléfono
INSERT INTO reservas (cliente, personas, fecha, hora)
VALUES ('Nuria Campos', 4, '2026-09-22', '20:00:00');
4 Insertar con solo stock
Inserta un plato indicando solo nombre, categoría y stock: 'Aceitunas aliñadas' (Entrantes, stock 30). El precio quedará sin valor (NULL).
Ver solución
-- Ejercicio 4: insertar sin precio
INSERT INTO platos (nombre, categoria, stock)
VALUES ('Aceitunas aliñadas', 'Entrantes', 30);
Sección B · UPDATE
5 Subir el precio de un plato
El 'Solomillo al whiskey' pasa a costar 27.50. Actualízalo filtrando
por nombre.
Ver solución
-- Ejercicio 5: subida de precio
UPDATE platos
SET precio = 27.50
WHERE nombre = 'Solomillo al whiskey';
6 Subida del 15 % a una categoría
Sube un 15 % el precio de todos los Pescados usando la fórmula
precio = precio * 1.15.
Ver solución
-- Ejercicio 6: reajuste global de pescados
UPDATE platos
SET precio = precio * 1.15
WHERE categoria = 'Pescados';
7 Rellenar el teléfono
La reserva de 'Diego Palacio' no tenía teléfono. Actualiza su registro guardando '699000111'.
Ver solución
-- Ejercicio 7: añadir teléfono
UPDATE reservas
SET telefono = '699000111'
WHERE cliente = 'Diego Palacio';
8 UPDATE con dos condiciones
Pon el plato 'Copa vino casa' como no activo (activo = 0)
y su stock a 0, usando un WHERE con nombre. Cambia las dos columnas a la vez.
Ver solución
-- Ejercicio 8: retirar un plato
UPDATE platos
SET activo = 0, stock = 0
WHERE nombre = 'Copa vino casa';
Sección C · DELETE
9 Cancelar una reserva
Borra la reserva de 'Sara Ballesteros' (su grupo canceló la comida del día 14).
Ver solución
-- Ejercicio 9: reserva cancelada
DELETE FROM reservas
WHERE cliente = 'Sara Ballesteros';
10 Limpieza de platos retirados
Borra todos los platos que estén marcados como no activos (activo = 0).
Ver solución
-- Ejercicio 10: fuera platos retirados
DELETE FROM platos
WHERE activo = 0;
Sección D · Funciones
11 Etiquetas en mayúsculas
Devuelve el nombre en mayúsculas (UPPER) y una columna etiqueta
con CONCAT(nombre, ' · ', categoria), para todos los platos de la tabla.
Ver solución
-- Ejercicio 11: etiquetas formateadas
SELECT UPPER(nombre) AS mayusculas,
CONCAT(nombre, ' · ', categoria) AS etiqueta
FROM platos;
12 Precio con IVA
Devuelve nombre, precio y el precio con un 21 % de IVA
redondeado a 2 decimales con el alias precio_con_iva.
Ver solución
-- Ejercicio 12: IVA incluido
SELECT nombre,
precio,
ROUND(precio * 1.21, 2) AS precio_con_iva
FROM platos;
13 Días hasta la reserva
Muestra cliente, fecha y los días que faltan hasta cada
reserva con DATEDIFF(fecha, CURDATE()), como columna dias_restantes.
Ver solución
-- Ejercicio 13: cuenta atrás
SELECT cliente,
fecha,
DATEDIFF(fecha, CURDATE()) AS dias_restantes
FROM reservas;
Sección E · CASE WHEN
14 Clasificar la carta
Devuelve nombre, precio y una columna gama con CASE: si el precio
es menor de 8 → 'Económico'; si es menor o igual a 16 →
'Normal'; si no → 'Premium'.
Ver solución
-- Ejercicio 14: gama según precio
SELECT nombre,
precio,
CASE
WHEN precio < 8 THEN 'Económico'
WHEN precio <= 16 THEN 'Normal'
ELSE 'Premium'
END AS gama
FROM platos;
15 Traducir la categoría
Con la forma simple de CASE, traduce la categoria: 'Arroces' →
'Cocina de fuego', 'Carnes' → 'Parrilla', el resto →
'Otras', en la columna tipo_cocina.
Ver solución
-- Ejercicio 15: CASE simple
SELECT nombre,
categoria,
CASE categoria
WHEN 'Arroces' THEN 'Cocina de fuego'
WHEN 'Carnes' THEN 'Parrilla'
ELSE 'Otras'
END AS tipo_cocina
FROM platos;
16 🏆 Proyecto integrador: la operación de cierre
Crea el fichero cierre_servicio.sql con un pequeño guion de gestión sobre
tw_restaurante que haga una sola consulta final de control (la verás abajo) y
antes, tres cambios de datos:
- INSERT una nueva reserva del cliente
'Rocío Sevilla', 2 personas, en'2026-09-25'a las'20:30:00'. - UPDATE sube un 5 % el precio de todos los Postres
(
precio = precio * 1.05). - DELETE las reservas anteriores a
'2026-09-14'. - Consulta final
SELECT:nombre,preciocon ROUND a 2 decimales comoprecio_final, y una columnagamacon CASE (menor de 8 →'Económico', menor o igual a 16 →'Normal', si no →'Premium'), de la tablaplatos, ordenada por precio descendente y filtrada conWHERE: solo categorías'Entrantes','Carnes'o'Postres'.
Ver una solución posible
-- Informe: operación de cierre del restaurante
INSERT INTO reservas (cliente, personas, fecha, hora)
VALUES ('Rocío Sevilla', 2, '2026-09-25', '20:30:00');
UPDATE platos
SET precio = precio * 1.05
WHERE categoria = 'Postres';
DELETE FROM reservas
WHERE fecha < '2026-09-14';
SELECT nombre,
ROUND(precio, 2) AS precio_final,
CASE
WHEN precio < 8 THEN 'Económico'
WHEN precio <= 16 THEN 'Normal'
ELSE 'Premium'
END AS gama
FROM platos
WHERE categoria IN ('Entrantes', 'Carnes', 'Postres')
ORDER BY precio DESC;
📝 Examen del Bloque 2
Dos partes: un test teórico autoevaluable (mínimo 70 %) y un reto práctico de autocorrección con laboratorio.
Parte B · Reto «cierre de servicio»
Crea cierre_servicio.sql: un guion con un INSERT, un UPDATE, un DELETE y una consulta final
que devuelva nombre, precio con ROUND y una columna gama con
CASE, ordenada por precio descendente. Tu SQL no se ejecuta en el laboratorio: se valida con
reglas automáticas. Mínimo para aprobar: 6 de 8 casillas.
Cumplidos: 0 / 8