🧪 Taller de Laboratorio
vistas

DML en Vivo: INSERT, UPDATE, DELETE y SELECT Real

Otra vez PostgreSQL de verdad, compilado a WebAssembly, corriendo enteramente en tu navegador. Esta vez no vas a crear tablas: vas a llenarlas, modificarlas, borrar con cuidado y sobre todo consultarlas — viendo en vivo qué filas exactas selecciona cada WHERE antes de confiar en él.

RC
Ing. Roy Carrasco
Facultad de Ingeniería de Sistemas · UAB

Bienvenido

Este taller es la práctica de laboratorio de DML y SELECT básico en PostgreSQL. No vuelve a explicar la teoría desde cero —asume que ya la viste— y en cambio te da un PostgreSQL real para insertar, actualizar, borrar y consultar datos, viendo exactamente lo que responde el motor.

📎 Prerrequisito

Si todavía no viste la teoría, repasa primero DML y SELECT básico en PostgreSQL antes de continuar. Este taller reconstruye el mismo esquema (CLIENTE, PRODUCTO, PEDIDO, DETALLE_PEDIDO) de la guía de DDL y lo va llenando con datos a medida que avanzas.

⚠️ Todo vive en la memoria de esta pestaña

Esta página corre su propia base de datos, independiente de cualquier otro taller que hayas abierto antes. Existe solo mientras esta pestaña siga abierta: si recargas la página, la cierras, o navegas a otra guía, se pierde todo y hay que empezar de nuevo desde "Prepara tu base de datos". Si te equivocás y querés reiniciar sin recargar, usa el botón "Reiniciar base de datos" de abajo.

✍️ Lo escribís vos

Cada bloque parte vacío. El enunciado te dice qué tenés que lograr — el código SQL lo escribís de cero.

🩻 Errores reales

Los mensajes de error que vas a ver son exactamente los que da PostgreSQL en producción.

🧩 Progresivo

Los datos que insertes en la sección 1 son los que vas a actualizar, borrar y consultar en el resto de la guía.

La base de datos está vacía. Baja a "Prepara tu base de datos" para empezar.

Zona de pruebas libres

Este bloque queda disponible durante toda la guía. Usalo en cualquier momento para probar una idea propia, revisar el estado de una tabla con SELECT * FROM tabla;, o experimentar con algo que se te ocurra a mitad de un ejercicio — sin desordenar los bloques guiados.

🧪 Escribe cualquier sentencia SQL

Prepara tu base de datos

Este bloque no es un ejercicio — ya viene resuelto. Reconstruye las cuatro tablas de la guía de DDL y las deja pobladas con un catálogo inicial de clientes y productos, para que el resto del taller tenga datos reales sobre los cuales trabajar. Ejecútalo tal cual, una sola vez, antes de seguir.

Qué hace este bloque

Crea cliente, producto, pedido y detalle_pedido con las mismas restricciones y claves foráneas de la guía de DDL, e inserta 5 clientes y 7 productos (uno de ellos, "Webcam HD", ya inactivo). Las tablas pedido y detalle_pedido quedan vacías a propósito: vas a llenarlas vos en la sección siguiente.

🏗️ Ejecuta esta preparación tal cual
Confirma los ids

El resultado final debería mostrarte 5 clientes con cliente_id del 1 al 5, en el mismo orden en que fueron insertados. El resto de esta guía asume exactamente esos ids — si algo no coincide, usa "🔄 Reiniciar base de datos" y vuelve a ejecutar este bloque.

1. INSERT: carga tus propios datos

El catálogo de clientes y productos ya existe. Ahora te toca registrar pedidos reales — y algún error a propósito para comprobar que un INSERT con varias filas es todo o nada.

Enunciado — 1.1

Inserta dos clientes nuevos en una sola instrucción INSERT: 'Jorge Peña' y 'Carla Núñez'.

🗄️ Ejercicio 1.1 — Dos clientes en un solo INSERT
Enunciado — 1.2

Registra un pedido para cliente_id = 1 (Ana Gutiérrez), sin especificar la fecha (deja que use su DEFAULT), y agrega RETURNING pedido_id para ver qué id le tocó. Justo debajo, en una segunda sentencia dentro del mismo bloque, inserta en detalle_pedido dos filas para ese pedido: producto_id = 1 con cantidad = 2, y producto_id = 3 con cantidad = 1.

🗄️ Ejercicio 1.2 — Primer pedido con RETURNING
Enunciado — 1.3

Registra un segundo pedido para cliente_id = 2 (Marco Flores). Inserta en detalle_pedido tres filas: producto_id = 2 cantidad 1, producto_id = 4 cantidad 1, y producto_id = 5 cantidad 3.

🗄️ Ejercicio 1.3 — Segundo pedido
Enunciado — 1.4

Registra un tercer pedido para cliente_id = 3 (Lucía Paredes), con una fila de detalle: producto_id = 7 cantidad 2.

🗄️ Ejercicio 1.4 — Tercer pedido

1.5 — Comprueba el todo o nada: intenta insertar dos productos en una sola instrucción: 'Cargador USB-C' a 45.00 (válido) y 'Cable roto' a -10.00 (viola el CHECK de precio positivo).

💥 Ejercicio 1.5 — INSERT con una fila inválida
Confirma con un SELECT

Corre SELECT * FROM producto WHERE producto_nombre = 'Cargador USB-C'; en la zona de pruebas libres. No debería devolver ninguna fila: aunque el primer valor era válido, el INSERT es una sola instrucción, y falló entera por culpa del segundo valor.

2. UPDATE con cuidado

Cada UPDATE de esta sección lleva un WHERE preciso. Fijate qué tan fácil sería, si te lo olvidás, modificar toda la tabla de una sola vez.

Enunciado — 2.1

Sube el precio de 'Cable HDMI' un 20% (usa precio = precio * 1.20), filtrando por producto_nombre.

🗄️ Ejercicio 2.1 — Sube un precio
Enunciado — 2.2

'Auriculares USB' ya tiene una venta registrada (la insertaste en el ejercicio 1.4), así que no se puede borrar sin más — pero se dejó de vender. Márcalo inactivo con UPDATE en lugar de borrarlo.

🗄️ Ejercicio 2.2 — Descontinúa sin perder el historial
Enunciado — 2.3

Actualiza 'Silla ergonómica' subiendo su precio un 5% y confirmando activo = true en la misma instrucción, separando ambas columnas con una coma dentro del SET.

🗄️ Ejercicio 2.3 — SET con dos columnas
No lo ejecutes aquí, pero pensalo

UPDATE producto SET precio = precio * 1.10; sin WHERE es sintácticamente válido, y subiría el precio del 100% de los productos de un solo golpe — incluidos los que acabás de dejar en un valor específico. Si querés sentir el efecto sin arriesgar el resto del taller, probalo en la zona de pruebas libres y después usa "🔄 Reiniciar base de datos" para volver a empezar.

3. DELETE, RESTRICT y CASCADE

Los mismos dos comportamientos de la guía de DDL, ahora vistos desde el lado de DML: qué pasa cuando borrás una fila que otra tabla está referenciando.

3.1 — Intenta borrar un producto con ventas: 'Teclado mecánico' (producto_id = 1) ya está referenciado en detalle_pedido desde el ejercicio 1.2, y esa clave foránea usa ON DELETE RESTRICT.

💥 Ejercicio 3.1 — DELETE bloqueado por RESTRICT

3.2 — Borra el pedido de Lucía Paredes (pedido_id = 3, del ejercicio 1.4). Su clave foránea desde detalle_pedido usa ON DELETE CASCADE: comprueba con un SELECT qué pasó con su detalle.

🗄️ Ejercicio 3.2 — DELETE con CASCADE
DELETE nunca es DROP TABLE

DELETE FROM producto; sin WHERE borraría todas las filas de producto, pero la tabla —estructura, columnas y restricciones— seguiría existiendo, vacía. No lo ejecutes acá (arruinaría el resto del taller): es sintácticamente válido, y esa es justamente la trampa. Es distinto de DROP TABLE producto;, que elimina la tabla entera, y de TRUNCATE TABLE producto;, que vacía la tabla más rápido que un DELETE y reinicia el contador IDENTITY.

4. SELECT básico y alias

Ya hay datos reales cargados. Empezamos por lo más simple: elegir columnas, renombrarlas con AS, y eliminar duplicados con DISTINCT.

Enunciado — 4.1

Selecciona producto_nombre y precio de todos los productos, renombrando la columna precio como precio_unitario con AS.

🗄️ Ejercicio 4.1 — SELECT con alias
Enunciado — 4.2

Antes de ejecutar, predice: ¿cuántas filas distintas puede devolver la columna activo de producto? Después escribe la consulta con DISTINCT para comprobarlo.

🗄️ Ejercicio 4.2 — DISTINCT

5. WHERE en profundidad

BETWEEN, IN, LIKE e IS NULL, uno por uno, sobre los datos que ya cargaste.

Enunciado — 5.1

Selecciona producto_nombre y precio de los productos activos con precio entre 50 y 300 (ambos límites incluidos).

🗄️ Ejercicio 5.1 — BETWEEN y AND
Enunciado — 5.2

Selecciona cliente_nombre de los clientes cuyo cliente_id esté en la lista (1, 3, 6, 7).

🗄️ Ejercicio 5.2 — IN
Enunciado — 5.3

Selecciona producto_nombre de los productos cuyo nombre contenga la palabra "USB" en cualquier posición.

🗄️ Ejercicio 5.3 — LIKE
Enunciado — 5.4

Agrega a pedido una columna fecha_entrega DATE (puede quedar sin definir). Luego, en una segunda sentencia, registra la fecha de entrega de hoy solo para el pedido_id = 1.

🗄️ Ejercicio 5.4 — ALTER TABLE + UPDATE

5.5 — Encuentra los pedidos sin entrega: selecciona todas las columnas de pedido donde fecha_entrega todavía no tiene valor.

🗄️ Ejercicio 5.5 — IS NULL
Probá el error clásico

Bajá a la zona de pruebas libres y escribí SELECT * FROM pedido WHERE fecha_entrega = NULL;. Vas a ver que no devuelve ninguna fila, ni siquiera las que sí tienen fecha_entrega en NULL — la prueba en vivo de por qué = NULL nunca funciona.

6. ORDER BY y LIMIT

Ordenar el resultado y cortarlo a un tamaño manejable — la base de la paginación.

Enunciado — 6.1

Selecciona producto_nombre y precio de los productos activos, ordenados de mayor a menor precio.

🗄️ Ejercicio 6.1 — ORDER BY DESC
Enunciado — 6.2

Selecciona producto_nombre, precio y activo de todos los productos, ordenados primero por activo descendente (los activos primero) y, dentro de cada grupo, por precio ascendente.

🗄️ Ejercicio 6.2 — Orden por dos columnas
Enunciado — 6.3

Con los productos ordenados de mayor a menor precio, trae la "segunda página" de 3: salta los 3 más caros y trae los 3 siguientes.

🗄️ Ejercicio 6.3 — LIMIT con OFFSET

Reto final: un día de operaciones

Sin reiniciar la base de datos, resuelve estos tres desafíos combinando todo lo practicado en este taller. Todavía no viste JOIN (es la próxima guía) — no lo necesitás para nada de esto.

Requisitos
  • 1. Inserta un cliente nuevo (el nombre que quieras) y registra un pedido para ese cliente con al menos 2 filas en detalle_pedido. Usa RETURNING para conocer el pedido_id generado antes de insertar el detalle.
  • 2. En una única instrucción UPDATE, sube un 15% el precio de todos los productos activos con precio menor a 100. Pensá primero cuáles productos cumplen esa condición.
  • 3. Escribe un SELECT que muestre producto_nombre y precio (con alias precio_unitario) de los 3 productos activos más caros, ordenados de mayor a menor.
🏆 Resuelve aquí el reto

Repaso

Seis preguntas cortas sobre lo que acabas de observar en vivo. Tu progreso se guarda automáticamente en este navegador.

0 / 0
actividades correctas en toda la guía
Selección múltiple

En el ejercicio 1.5 intentaste insertar dos productos en una sola instrucción: uno válido y otro con precio negativo. ¿Qué pasó de verdad?

Verdadero o falso

En el ejercicio 3.1, PostgreSQL te dejó borrar 'Teclado mecánico' sin problema, porque DELETE siempre tiene prioridad sobre las claves foráneas.

Selección múltiple

En el ejercicio 3.2 borraste el pedido de Lucía Paredes y sus filas de detalle_pedido desaparecieron solas, sin que las borraras a mano. ¿Por qué?

Clasificación

Clasifica cada instrucción según lo que le pasaría a la tabla producto y a sus filas si la ejecutaras (no la ejecutes: solo razona).

DELETE FROM producto;
DROP TABLE producto;
TRUNCATE TABLE producto;

Selección múltiple

En el ejercicio 5.5 filtraste con fecha_entrega IS NULL. ¿Por qué WHERE fecha_entrega = NULL nunca hubiera funcionado, ni siquiera para las filas que sí tienen NULL ahí?

Completar

Sobre el ejercicio 6.3: SELECT producto_nombre, precio FROM producto ORDER BY precio DESC LIMIT 3 OFFSET 3;

1. Antes de aplicar LIMIT y OFFSET, el resultado queda ordenado de .

2. OFFSET 3 hace que la consulta .

Cheat Sheet del taller

InstrucciónPara qué sirve
INSERT INTO tabla (cols) VALUES (...)Agrega una o varias filas nuevas (todo o nada si son varias).
... RETURNING columnaDevuelve datos de la fila insertada (útil para ids generados por IDENTITY).
UPDATE tabla SET col = valor WHERE ...Modifica filas existentes que cumplen la condición.
DELETE FROM tabla WHERE ...Elimina filas que cumplen la condición (sin WHERE, elimina todas).
SELECT cols AS alias FROM tablaConsulta columnas específicas, opcionalmente renombradas.
DISTINCTElimina filas duplicadas del resultado.
WHERE (=, BETWEEN, IN, LIKE, IS NULL)Filtra qué filas se incluyen.
ORDER BY col ASC/DESCOrdena el resultado (ASC por defecto).
LIMIT n OFFSET mCorta el resultado a n filas, saltando las primeras m (paginación).
Situación que viviste en este tallerMensaje real de PostgreSQL
Ejercicio 1.5: violar un CHECK dentro de un INSERT múltiplenew row for relation "producto" violates check constraint "..."
Ejercicio 3.1: borrar una fila padre protegida por RESTRICTupdate or delete on table "producto" violates foreign key constraint "..." on table "detalle_pedido"

¿Sabías que...?

🐘 RETURNING no es SQL estándar

Es una extensión propia de PostgreSQL. Otros motores resuelven "¿qué id generó mi INSERT?" de formas distintas —SQL Server usa OUTPUT, MySQL expone LAST_INSERT_ID()— sin una cláusula tan directa como RETURNING dentro de la misma instrucción.

🔢 Un INSERT fallido puede dejar huecos en el IDENTITY

El contador de una columna IDENTITY no forma parte de la transacción: aunque tu INSERT fallara por completo en el ejercicio 1.5, PostgreSQL ya había "gastado" los próximos valores de la secuencia antes de detectar el error. Por eso no es raro ver ids no consecutivos en tablas reales.

🔍 Sin índice, WHERE revisa fila por fila

Cada consulta de esta guía recorrió la tabla entera comparando fila por fila contra la condición del WHERE. Con miles de filas eso se nota — el tema de índices y EXPLAIN, más adelante en el curso, es exactamente sobre cómo evitarlo.