Día 6 – INSERT, UPDATE, DELETE: modificar datos de forma segura

Página de inicio

Día 6 – INSERT, UPDATE, DELETE: modificar datos de forma segura

Hoy vas a aprender a modificar datos en la base de datos. Hasta ahora solo has leído información con SELECT. Pero en el mundo real necesitas crear, actualizar y eliminar registros.

Estas operaciones son poderosas pero peligrosas. Un UPDATE sin WHERE puede modificar toda la tabla. Un DELETE sin WHERE puede borrar todos tus datos. Por eso aprenderás no solo cómo hacerlo, sino cómo hacerlo de forma segura.


Escenario del día

Tu equipo te pide realizar varias tareas:

  • Añadir nuevos productos al catálogo
  • Actualizar el stock después de una venta
  • Corregir el email de un usuario
  • Eliminar productos descontinuados
  • Registrar un nuevo pedido con sus detalles

Sin estas operaciones, tu base de datos sería de solo lectura. Con lo que aprenderás hoy, podrás mantener tus datos actualizados y precisos.


⚠️ Regla de oro: SIEMPRE haz backup

Antes de hacer cualquier UPDATE o DELETE en producción:

  1. Haz un backup de la tabla o base de datos
  2. Prueba la consulta con SELECT primero
  3. Usa transacciones para poder revertir cambios
  4. Verifica con WHERE que estás afectando las filas correctas

Nunca, jamás, ejecutes UPDATE o DELETE sin WHERE en producción (a menos que realmente quieras modificar/borrar toda la tabla).


1. INSERT – Añadir nuevos registros

INSERT añade nuevas filas a una tabla.

Sintaxis básica

INSERT INTO tabla (columna1, columna2, columna3)
VALUES (valor1, valor2, valor3);

Insertar un solo registro

-- Añadir un nuevo usuario
INSERT INTO usuarios (nombre, email, fecha_registro, pais)
VALUES ('Roberto Gomez', 'roberto.gomez@email.com', '2024-05-01', 'España');

Nota: No incluimos id porque es SERIAL (se genera automáticamente).

Verificar que se insertó:

SELECT * FROM usuarios WHERE email = 'roberto.gomez@email.com';

Insertar sin especificar columnas (no recomendado)

-- ⚠️ Funciona pero es frágil
INSERT INTO usuarios
VALUES (11, 'Andrea Lopez', 'andrea.lopez@email.com', '2024-05-02', 'México');

Problema: Si cambias el orden de las columnas en la tabla, esta consulta falla.

Mejor práctica: Siempre especifica las columnas explícitamente.

Insertar con valores por defecto

-- La fecha_registro usa DEFAULT (CURRENT_DATE)
INSERT INTO usuarios (nombre, email, pais)
VALUES ('Luis Torres', 'luis.torres@email.com', 'Argentina');

Insertar múltiples registros a la vez

-- Añadir varios productos de golpe
INSERT INTO productos (nombre, precio, categoria, stock)
VALUES 
    ('Mouse Inalambrico Logitech', 29.99, 'Accesorios', 60),
    ('Teclado Gaming Corsair', 149.99, 'Accesorios', 25),
    ('Cable USB-C 2m', 12.99, 'Accesorios', 100);

Mucho más eficiente que hacer 3 INSERT separados.

Verificar:

SELECT * FROM productos WHERE nombre LIKE '%Logitech%' OR nombre LIKE '%Corsair%';

Insertar y obtener el ID generado (RETURNING)

PostgreSQL tiene una característica muy útil: puedes obtener los valores generados automáticamente.

-- Insertar usuario y obtener su ID
INSERT INTO usuarios (nombre, email, pais)
VALUES ('Marina Silva', 'marina.silva@email.com', 'Brasil')
RETURNING id, nombre, email;

Resultado:

idnombreemail
12Marina Silvamarina.silva@email.com

Esto es muy útil cuando necesitas el ID para insertar registros relacionados inmediatamente después.

Insertar desde otra tabla (INSERT SELECT)

-- Crear tabla de respaldo
CREATE TABLE usuarios_backup (
    id INTEGER,
    nombre VARCHAR(100),
    email VARCHAR(100),
    fecha_registro DATE,
    pais VARCHAR(50)
);

-- Copiar usuarios de España
INSERT INTO usuarios_backup (id, nombre, email, fecha_registro, pais)
SELECT id, nombre, email, fecha_registro, pais
FROM usuarios
WHERE pais = 'España';

Verificar:

SELECT COUNT(*) FROM usuarios_backup;

2. UPDATE – Modificar registros existentes

UPDATE cambia valores de filas que ya existen.

Sintaxis básica

UPDATE tabla
SET columna1 = valor1, columna2 = valor2
WHERE condicion;

⚠️ IMPORTANTÍSIMO: El WHERE es opcional pero casi siempre necesario. Sin WHERE actualizas TODAS las filas.

Actualizar un solo campo

-- Cambiar el email de un usuario
UPDATE usuarios
SET email = 'ana.garcia.nuevo@email.com'
WHERE id = 1;

Antes de ejecutar, verifica qué vas a cambiar:

-- 1. Primero mira qué vas a modificar
SELECT id, nombre, email 
FROM usuarios 
WHERE id = 1;

-- 2. Luego ejecuta el UPDATE
UPDATE usuarios
SET email = 'ana.garcia.nuevo@email.com'
WHERE id = 1;

-- 3. Verifica el cambio
SELECT id, nombre, email 
FROM usuarios 
WHERE id = 1;

Actualizar múltiples campos

-- Actualizar varios campos a la vez
UPDATE productos
SET 
    precio = 1399.99,
    stock = 20
WHERE id = 1;

Actualizar basándose en condiciones

-- Reducir stock después de una venta
UPDATE productos
SET stock = stock - 3
WHERE id = 4;

Importante: stock = stock - 3 usa el valor actual para calcular el nuevo.

Actualizar múltiples registros

-- Aumentar 10% el precio de todos los productos de Electronica
UPDATE productos
SET precio = precio * 1.10
WHERE categoria = 'Electronica';

Verificar antes:

-- Ver qué productos se afectarán
SELECT nombre, categoria, precio, ROUND(precio * 1.10, 2) AS precio_nuevo
FROM productos
WHERE categoria = 'Electronica';

UPDATE con RETURNING

-- Actualizar y ver qué cambió
UPDATE productos
SET stock = stock - 1
WHERE nombre = 'iPhone 15 Pro'
RETURNING id, nombre, stock;

UPDATE con subconsultas

-- Actualizar el total de un pedido basándose en sus detalles
UPDATE pedidos
SET total = (
    SELECT SUM(cantidad * precio_unitario)
    FROM detalle_pedidos
    WHERE pedido_id = pedidos.id
)
WHERE id = 1;

UPDATE con JOIN (PostgreSQL)

-- Aplicar descuento del 5% a productos vendidos más de 2 veces
UPDATE productos
SET precio = precio * 0.95
FROM (
    SELECT producto_id
    FROM detalle_pedidos
    GROUP BY producto_id
    HAVING COUNT(*) > 2
) AS productos_populares
WHERE productos.id = productos_populares.producto_id;

3. DELETE – Eliminar registros

DELETE elimina filas de una tabla.

Sintaxis básica

DELETE FROM tabla
WHERE condicion;

⚠️ CRÍTICO: Sin WHERE, borras TODA la tabla.

Eliminar un registro específico

-- Primero verifica qué vas a borrar
SELECT * FROM usuarios WHERE id = 11;

-- Luego elimina
DELETE FROM usuarios WHERE id = 11;

-- Verifica que se borró
SELECT * FROM usuarios WHERE id = 11;  -- No debería devolver nada

Eliminar múltiples registros

-- Borrar productos sin stock
DELETE FROM productos
WHERE stock = 0;

DELETE con RETURNING

-- Eliminar y ver qué se borró
DELETE FROM productos
WHERE categoria = 'Muebles' AND stock < 5
RETURNING id, nombre, categoria, stock;

Eliminar registros relacionados (con cuidado)

-- ❌ ESTO PUEDE DAR ERROR si hay pedidos de Ana
DELETE FROM usuarios WHERE id = 1;

Error: Cannot delete because there are related records in pedidos.

Solución 1: Eliminar primero los pedidos (cascada manual)

-- Primero borra los detalles de pedidos
DELETE FROM detalle_pedidos
WHERE pedido_id IN (SELECT id FROM pedidos WHERE usuario_id = 1);

-- Luego borra los pedidos
DELETE FROM pedidos WHERE usuario_id = 1;

-- Finalmente borra el usuario
DELETE FROM usuarios WHERE id = 1;

Solución 2: ON DELETE CASCADE (configurado en la creación de tablas)

Si las tablas tienen ON DELETE CASCADE, borrar el usuario borra automáticamente sus pedidos.

DELETE vs TRUNCATE

-- DELETE: Borra filas una por una (más lento, puedes usar WHERE)
DELETE FROM usuarios_backup;

-- TRUNCATE: Vacía la tabla instantáneamente (más rápido, sin WHERE)
TRUNCATE TABLE usuarios_backup;

-- TRUNCATE con CASCADE (borra también tablas relacionadas)
TRUNCATE TABLE usuarios CASCADE;

Diferencias:

AspectoDELETETRUNCATE
WHERENo
VelocidadLento (fila por fila)Muy rápido
ROLLBACKSí (dentro de transacción)
Reinicia SERIALNo
TriggersSí se ejecutanNo

4. Transacciones: Control total con COMMIT y ROLLBACK

Las transacciones te permiten agrupar varias operaciones y revertirlas si algo sale mal.

Conceptos básicos

BEGIN;              -- Inicia una transacción
-- Tus operaciones aquí
COMMIT;             -- Confirma los cambios
-- O
ROLLBACK;           -- Cancela los cambios

Ejemplo: Transferencia bancaria

BEGIN;

-- Restar dinero de una cuenta
UPDATE cuentas SET saldo = saldo - 100 WHERE id = 1;

-- Sumar dinero a otra cuenta
UPDATE cuentas SET saldo = saldo + 100 WHERE id = 2;

-- Si todo está bien, confirmar
COMMIT;

-- Si algo falla, cancelar
-- ROLLBACK;

Si algo falla entre ambos UPDATE, puedes hacer ROLLBACK y ninguno se aplica. Todo o nada.

Ejemplo: Registrar un pedido completo

BEGIN;

-- 1. Crear el pedido
INSERT INTO pedidos (usuario_id, fecha, total)
VALUES (1, CURRENT_DATE, 429.98)
RETURNING id;  -- Supongamos que devuelve id = 6

-- 2. Añadir detalles del pedido
INSERT INTO detalle_pedidos (pedido_id, producto_id, cantidad, precio_unitario)
VALUES 
    (6, 3, 1, 349.99),  -- Auriculares Sony
    (6, 5, 1, 79.99);   -- Ratón Gaming

-- 3. Actualizar stock de productos
UPDATE productos SET stock = stock - 1 WHERE id = 3;
UPDATE productos SET stock = stock - 1 WHERE id = 5;

-- 4. Verificar que todo está bien
SELECT * FROM pedidos WHERE id = 6;
SELECT * FROM detalle_pedidos WHERE pedido_id = 6;
SELECT nombre, stock FROM productos WHERE id IN (3, 5);

-- Si todo está correcto:
COMMIT;

-- Si algo falló:
-- ROLLBACK;

Ventajas:

  • ✅ Si falla cualquier paso, puedes cancelar todo
  • ✅ Garantiza consistencia de datos
  • ✅ Evita estados intermedios incorrectos

Buenas prácticas con transacciones

-- Buena práctica: Envolver operaciones críticas
BEGIN;

-- Hacer backup virtual
CREATE TEMP TABLE backup_productos AS 
SELECT * FROM productos WHERE categoria = 'Electronica';

-- Realizar cambios
UPDATE productos 
SET precio = precio * 0.90 
WHERE categoria = 'Electronica';

-- Verificar resultado
SELECT nombre, precio FROM productos WHERE categoria = 'Electronica';

-- Si está bien: COMMIT
-- Si está mal: ROLLBACK y revisar
COMMIT;

5. Casos prácticos del día a día

Registrar una venta completa

BEGIN;

-- Paso 1: Crear el pedido y obtener su ID
WITH nuevo_pedido AS (
    INSERT INTO pedidos (usuario_id, fecha, total)
    VALUES (2, CURRENT_DATE, 0)  -- Total lo calculamos después
    RETURNING id
)
-- Paso 2: Insertar los productos del pedido
INSERT INTO detalle_pedidos (pedido_id, producto_id, cantidad, precio_unitario)
SELECT 
    (SELECT id FROM nuevo_pedido),
    producto_id,
    cantidad,
    precio
FROM (VALUES 
    (1, 1, 1299.99),  -- Laptop
    (4, 1, 129.99)    -- Teclado
) AS items(producto_id, cantidad, precio);

-- Paso 3: Actualizar el total del pedido
UPDATE pedidos
SET total = (
    SELECT SUM(cantidad * precio_unitario)
    FROM detalle_pedidos
    WHERE pedido_id = (SELECT id FROM nuevo_pedido)
)
WHERE id = (SELECT id FROM nuevo_pedido);

-- Paso 4: Reducir stock
UPDATE productos p
SET stock = stock - dp.cantidad
FROM detalle_pedidos dp
WHERE p.id = dp.producto_id
AND dp.pedido_id = (SELECT id FROM nuevo_pedido);

COMMIT;

Actualizar precios con histórico

-- Crear tabla de histórico primero
CREATE TABLE IF NOT EXISTS historico_precios (
    id SERIAL PRIMARY KEY,
    producto_id INTEGER,
    precio_anterior DECIMAL(10,2),
    precio_nuevo DECIMAL(10,2),
    fecha_cambio TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

BEGIN;

-- Guardar precios antiguos antes de cambiar
INSERT INTO historico_precios (producto_id, precio_anterior, precio_nuevo)
SELECT 
    id,
    precio,
    precio * 1.05  -- Aumento del 5%
FROM productos
WHERE categoria = 'Accesorios';

-- Actualizar precios
UPDATE productos
SET precio = precio * 1.05
WHERE categoria = 'Accesorios';

COMMIT;

Limpiar datos inconsistentes

BEGIN;

-- Encontrar pedidos sin detalles (datos huérfanos)
WITH pedidos_vacios AS (
    SELECT p.id
    FROM pedidos p
    LEFT JOIN detalle_pedidos dp ON p.id = dp.pedido_id
    WHERE dp.id IS NULL
)
-- Eliminarlos
DELETE FROM pedidos
WHERE id IN (SELECT id FROM pedidos_vacios)
RETURNING id, fecha, total;

COMMIT;

Migrar datos entre tablas

BEGIN;

-- Crear tabla de usuarios VIP
CREATE TABLE IF NOT EXISTS usuarios_vip (
    id INTEGER PRIMARY KEY,
    nombre VARCHAR(100),
    email VARCHAR(100),
    fecha_registro DATE,
    pais VARCHAR(50),
    gasto_total DECIMAL(10,2)
);

-- Copiar usuarios que gastaron más de 1000€
INSERT INTO usuarios_vip (id, nombre, email, fecha_registro, pais, gasto_total)
SELECT 
    u.id,
    u.nombre,
    u.email,
    u.fecha_registro,
    u.pais,
    SUM(p.total) AS gasto_total
FROM usuarios u
INNER JOIN pedidos p ON u.id = p.usuario_id
GROUP BY u.id, u.nombre, u.email, u.fecha_registro, u.pais
HAVING SUM(p.total) > 1000;

COMMIT;

-- Verificar
SELECT * FROM usuarios_vip ORDER BY gasto_total DESC;

6. Restricciones y validaciones

UNIQUE – Evitar duplicados

-- Intentar insertar email duplicado
INSERT INTO usuarios (nombre, email, pais)
VALUES ('Test User', 'ana.garcia@email.com', 'España');
-- ERROR: duplicate key value violates unique constraint

CHECK – Validar valores

-- Añadir restricción (si no existe ya)
ALTER TABLE productos
ADD CONSTRAINT precio_positivo CHECK (precio > 0);

-- Intentar insertar precio negativo
INSERT INTO productos (nombre, precio, categoria, stock)
VALUES ('Producto malo', -10.00, 'Test', 0);
-- ERROR: new row violates check constraint "precio_positivo"

NOT NULL – Campos obligatorios

-- Intentar insertar sin nombre
INSERT INTO usuarios (email, pais)
VALUES ('test@email.com', 'España');
-- ERROR: null value in column "nombre" violates not-null constraint

Foreign Keys – Integridad referencial

-- Intentar crear pedido con usuario inexistente
INSERT INTO pedidos (usuario_id, fecha, total)
VALUES (999, CURRENT_DATE, 100.00);
-- ERROR: insert or update violates foreign key constraint

7. Errores comunes (y cómo evitarlos)

Error 1: UPDATE/DELETE sin WHERE

-- ❌ PELIGRO: Actualiza TODOS los productos
UPDATE productos SET precio = 0;

-- ✅ CORRECTO: Solo los que queremos
UPDATE productos SET precio = 0 WHERE id = 999;

Protección: Siempre haz SELECT primero:

-- 1. Ver qué se afectará
SELECT * FROM productos WHERE id = 999;

-- 2. Hacer el UPDATE
UPDATE productos SET precio = 0 WHERE id = 999;

Error 2: Olvidar COMMIT

BEGIN;
UPDATE productos SET stock = stock - 1 WHERE id = 1;
-- ⚠️ Si cierras la sesión sin COMMIT, se pierde el cambio
COMMIT;  -- ¡No olvides esto!

Error 3: Tipos de datos incompatibles

-- ❌ ERROR: Intentar insertar texto en campo numérico
INSERT INTO productos (nombre, precio, categoria, stock)
VALUES ('Test', 'cien euros', 'Test', 10);
-- ERROR: invalid input syntax for type numeric

Error 4: Violar restricciones de foreign key

-- ❌ No puedes borrar un usuario con pedidos
DELETE FROM usuarios WHERE id = 1;
-- ERROR: update or delete violates foreign key constraint

-- ✅ Solución: Borrar primero los pedidos (o usar CASCADE)
BEGIN;
DELETE FROM detalle_pedidos WHERE pedido_id IN (SELECT id FROM pedidos WHERE usuario_id = 1);
DELETE FROM pedidos WHERE usuario_id = 1;
DELETE FROM usuarios WHERE id = 1;
COMMIT;

8. Buenas prácticas

1. Siempre usa transacciones para operaciones críticas

BEGIN;
-- Tus operaciones
COMMIT;  -- o ROLLBACK si algo falla

2. Prueba con SELECT antes de UPDATE/DELETE

-- MAL
UPDATE productos SET precio = precio * 2 WHERE categoria = 'Electronica';

-- BIEN
SELECT nombre, precio, precio * 2 AS nuevo_precio 
FROM productos 
WHERE categoria = 'Electronica';
-- Revisar resultado, luego hacer UPDATE

3. Usa RETURNING para verificar cambios

UPDATE productos
SET stock = stock - 1
WHERE id = 5
RETURNING id, nombre, stock;

4. Haz backups antes de cambios masivos

-- Backup de tabla
CREATE TABLE productos_backup_20240501 AS
SELECT * FROM productos;

-- Ahora puedes hacer cambios con confianza

5. Limita UPDATE/DELETE en producción

-- Usar LIMIT para cambios graduales
DELETE FROM logs_antiguos
WHERE fecha < '2023-01-01'
LIMIT 1000;
-- Ejecutar varias veces en lugar de todo de golpe

6. Documenta cambios importantes

-- Malo: Sin contexto
UPDATE productos SET precio = precio * 1.15;

-- Bueno: Con comentario
-- Ajuste de precios Q2 2024 - Ticket #1234
-- Aprobado por: Juan Manager - 01/05/2024
UPDATE productos 
SET precio = precio * 1.15 
WHERE categoria IN ('Electronica', 'Accesorios');

9. Ejercicios prácticos

Intenta resolver estos ejercicios. Usa transacciones para poder revertir si algo sale mal.

  1. Inserta un nuevo usuario llamado «Patricia Navarro» con email «patricia.navarro@email.com» de Chile
  2. Inserta 3 productos nuevos en una sola operación
  3. Actualiza el stock de todos los productos de «Accesorios», aumentándolo en 10 unidades
  4. Crea un pedido completo para el usuario con id=3, con 2 productos, y actualiza sus stocks
  5. Incrementa 15% el precio de productos con stock menor a 20 unidades
  6. Corrige todos los emails que tienen «@email.com» a «@example.com»
  7. Elimina productos que nunca se han vendido y tienen stock 0
  8. Crea una tabla de auditoría y registra cambios de precio usando triggers o manualmente
  9. Encuentra y elimina pedidos duplicados (mismo usuario, misma fecha, mismo total)
  10. Migra usuarios de España a una nueva tabla «usuarios_europa»

💡 Consejo: Usa BEGIN; antes de cada ejercicio y ROLLBACK; si quieres deshacer, o COMMIT; si está bien.


10. Soluciones

Solución Ejercicio 1

INSERT INTO usuarios (nombre, email, pais, fecha_registro)
VALUES ('Patricia Navarro', 'patricia.navarro@email.com', 'Chile', CURRENT_DATE)
RETURNING id, nombre, email, pais;

Solución Ejercicio 2

INSERT INTO productos (nombre, precio, categoria, stock)
VALUES 
    ('Alfombrilla Gaming XXL', 24.99, 'Accesorios', 45),
    ('Hub USB 7 Puertos', 39.99, 'Accesorios', 30),
    ('Soporte Laptop Ajustable', 34.99, 'Accesorios', 20)
RETURNING id, nombre, precio;

Solución Ejercicio 3

BEGIN;

-- Ver estado actual
SELECT nombre, stock FROM productos WHERE categoria = 'Accesorios';

-- Actualizar
UPDATE productos
SET stock = stock + 10
WHERE categoria = 'Accesorios'
RETURNING nombre, stock;

COMMIT;

Solución Ejercicio 4

BEGIN;

-- Crear el pedido
INSERT INTO pedidos (usuario_id, fecha, total)
VALUES (3, CURRENT_DATE, 0)
RETURNING id;  -- Supongamos que devuelve 7

-- Añadir detalles (ajusta pedido_id al que obtuviste)
INSERT INTO detalle_pedidos (pedido_id, producto_id, cantidad, precio_unitario)
VALUES 
    (7, 6, 1, 299.00),   -- Monitor
    (7, 8, 2, 89.99);    -- Webcam x2

-- Actualizar total del pedido
UPDATE pedidos
SET total = (
    SELECT SUM(cantidad * precio_unitario)
    FROM detalle_pedidos
    WHERE pedido_id = 7
)
WHERE id = 7;

-- Reducir stock
UPDATE productos SET stock = stock - 1 WHERE id = 6;
UPDATE productos SET stock = stock - 2 WHERE id = 8;

-- Verificar
SELECT * FROM pedidos WHERE id = 7;
SELECT * FROM detalle_pedidos WHERE pedido_id = 7;

COMMIT;

Solución Ejercicio 5

BEGIN;

-- Ver qué se actualizará
SELECT nombre, precio, stock, ROUND(precio * 1.15, 2) AS precio_nuevo
FROM productos
WHERE stock < 20;

-- Actualizar
UPDATE productos
SET precio = precio * 1.15
WHERE stock < 20
RETURNING nombre, precio, stock;

COMMIT;

Solución Ejercicio 6

BEGIN;

-- Ver qué se cambiará
SELECT nombre, email, REPLACE(email, '@email.com', '@example.com') AS email_nuevo
FROM usuarios
WHERE email LIKE '%@email.com';

-- Actualizar
UPDATE usuarios
SET email = REPLACE(email, '@email.com', '@example.com')
WHERE email LIKE '%@email.com'
RETURNING nombre, email;

COMMIT;

Solución Ejercicio 7

BEGIN;

-- Encontrar productos a eliminar
SELECT p.id, p.nombre, p.stock
FROM productos p
LEFT JOIN detalle_pedidos dp ON p.id = dp.producto_id
WHERE dp.id IS NULL AND p.stock = 0;

-- Eliminar
DELETE FROM productos
WHERE stock = 0
AND id NOT IN (SELECT DISTINCT producto_id FROM detalle_pedidos WHERE producto_id IS NOT NULL)
RETURNING id, nombre, categoria;

COMMIT;

Solución Ejercicio 8

BEGIN;

-- Crear tabla de auditoría
CREATE TABLE IF NOT EXISTS auditoria_precios (
    id SERIAL PRIMARY KEY,
    producto_id INTEGER,
    nombre_producto VARCHAR(200),
    precio_anterior DECIMAL(10,2),
    precio_nuevo DECIMAL(10,2),
    usuario VARCHAR(50),
    fecha_cambio TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Registrar cambio antes de hacerlo
INSERT INTO auditoria_precios (producto_id, nombre_producto, precio_anterior, precio_nuevo, usuario)
SELECT 
    id,
    nombre,
    precio,
    ROUND(precio * 1.10, 2),
    CURRENT_USER
FROM productos
WHERE id = 1;

-- Hacer el cambio
UPDATE productos
SET precio = precio * 1.10
WHERE id = 1;

-- Ver auditoría
SELECT * FROM auditoria_precios ORDER BY fecha_cambio DESC;

COMMIT;

Solución Ejercicio 9

BEGIN;

-- Encontrar duplicados (quedarse con el ID menor)
WITH duplicados AS (
    SELECT 
        usuario_id,
        fecha,
        total,
        MIN(id) AS id_mantener,
        ARRAY_AGG(id) AS todos_ids
    FROM pedidos
    GROUP BY usuario_id, fecha, total
    HAVING COUNT(*) > 1
)
-- Eliminar duplicados (mantener solo el primero)
DELETE FROM pedidos
WHERE id IN (
    SELECT unnest(todos_ids)
    FROM duplicados
) AND id NOT IN (
    SELECT id_mantener
    FROM duplicados
)
RETURNING id, usuario_id, fecha, total;

COMMIT;

Solución Ejercicio 10

BEGIN;

-- Crear tabla de usuarios Europa
CREATE TABLE IF NOT EXISTS usuarios_europa (
    id INTEGER PRIMARY KEY,
    nombre VARCHAR(100),
    email VARCHAR(100),
    fecha_registro DATE,
    pais VARCHAR(50)
);

-- Copiar usuarios de España
INSERT INTO usuarios_europa (id, nombre, email, fecha_registro, pais)
SELECT id, nombre, email, fecha_registro, pais
FROM usuarios
WHERE pais = 'España'
RETURNING *;

-- Verificar
SELECT COUNT(*) FROM usuarios_europa;

COMMIT;

Resumen del Día 6

¡Excelente trabajo! Ahora dominas las operaciones para modificar datos de forma segura.

Has aprendido:

INSERT → Añadir nuevos registros (uno o múltiples)
UPDATE → Modificar registros existentes
DELETE → Eliminar registros
RETURNING → Ver qué cambió inmediatamente
Transacciones → BEGIN, COMMIT, ROLLBACK para control total
INSERT SELECT → Copiar datos entre tablas
Restricciones → UNIQUE, CHECK, NOT NULL, Foreign Keys
Buenas prácticas → Siempre hacer SELECT primero, usar transacciones, hacer backups

Clave del día:

  • NUNCA ejecutes UPDATE o DELETE sin WHERE en producción
  • SIEMPRE prueba con SELECT antes de modificar
  • USA transacciones para operaciones críticas (BEGIN/COMMIT/ROLLBACK)
  • VERIFICA con RETURNING qué cambió
  • HAZ backups antes de cambios masivos

Siguiente paso

En el Día 7 (último día del curso) aprenderás sobre índices y optimización: cómo hacer que tus consultas sean más rápidas, entender planes de ejecución y optimizar el rendimiento de tu base de datos.

También verás:

  • Cómo crear índices efectivos
  • Cuándo usar o no usar índices
  • Analizar planes de ejecución con EXPLAIN
  • Mejores prácticas de rendimiento

¡Nos vemos en el Día 7, el gran final!

Este sitio web utiliza cookies para que usted tenga la mejor experiencia de usuario. Si continúa navegando está dando su consentimiento para la aceptación de las mencionadas cookies y la aceptación de nuestra política de cookies, pinche el enlace para mayor información.

ACEPTAR
Aviso de cookies