cv.cm

Programación · Lenguajes de programación

Tutorial de SQL para principiantes

8 min de lectura

Respuesta corta

SQL es el lenguaje estándar para crear, consultar y modificar datos en bases de datos relacionales como PostgreSQL, MySQL y SQLite. Escribes instrucciones declarativas como SELECT, INSERT, UPDATE y DELETE, y la base de datos decide cómo ejecutarlas. Esta página enseña el diseño de tablas, el filtrado, los joins, la agrupación, las subconsultas, las funciones de ventana y las transacciones, y enumera las principales diferencias entre PostgreSQL, MySQL y SQLite.

Qué es SQL y para qué se usa

SQL (Structured Query Language, lenguaje de consulta estructurado) es el lenguaje estándar para trabajar con bases de datos relacionales, donde los datos se guardan en tablas de filas y columnas. Tú describes qué datos quieres y el motor de la base de datos decide cómo encontrarlos. SQL está normalizado por ISO/IEC 9075, y todos los gestores importantes implementan el núcleo del estándar más sus propias extensiones.

Desarrolladores, analistas de datos, ingenieros de datos y administradores de bases de datos usan SQL a diario: para guardar los datos de una aplicación, responder preguntas de negocio, crear informes y alimentar pipelines de datos. Los motores de código abierto más comunes son PostgreSQL, MySQL (y su fork MariaDB) y SQLite; entre los comerciales están Microsoft SQL Server y Oracle Database.

Obtén una base de datos y ejecuta tu primera consulta

La forma más fácil de empezar es SQLite, una base de datos sin servidor que se guarda en un solo archivo. Viene preinstalada en macOS y en la mayoría de los sistemas Linux. PostgreSQL y MySQL funcionan como servidores e incluyen los clientes de línea de comandos psql y mysql.

sqlite3 shop.db                      # SQLite: opens or creates a file
psql -U postgres -d shop             # PostgreSQL client
mysql -u root -p shop                # MySQL client
SELECT 'Hello, world!' AS greeting;
-- greeting
-- Hello, world!

Las palabras clave de SQL no distinguen mayúsculas de minúsculas. Escribir las palabras clave en mayúsculas y los nombres en minúsculas es una convención habitual que hace las consultas más fáciles de leer. Una instrucción termina con punto y coma, y -- inicia un comentario.

Crear tablas: tipos de datos y restricciones

La definición de una tabla enumera las columnas, sus tipos y las restricciones que mantienen los datos válidos. Esta página usa dos tablas, customers y orders, en todos los ejemplos.

CREATE TABLE customers (
  id    INTEGER PRIMARY KEY,
  name  VARCHAR(100) NOT NULL,
  city  VARCHAR(50)
);
CREATE TABLE orders (
  id          INTEGER PRIMARY KEY,
  customer_id INTEGER NOT NULL REFERENCES customers(id),
  amount      DECIMAL(10, 2) NOT NULL,
  ordered_on  DATE NOT NULL
);
INSERT INTO customers (id, name, city) VALUES
  (1, 'Ann', 'Oslo'), (2, 'Bo', 'Rome'), (3, 'Cy', 'Oslo');
INSERT INTO orders (id, customer_id, amount, ordered_on) VALUES
  (1, 1, 30.00, '2026-01-05'),
  (2, 1, 45.50, '2026-02-10'),
  (3, 2, 12.00, '2026-02-11');
TipoAlmacenaNotas
INTEGER, BIGINTnúmeros enterosusa BIGINT para IDs grandes
DECIMAL(p, s)decimales exactosúsalo para dinero, nunca FLOAT
VARCHAR(n), TEXTcadenas de textoTEXT no está en el estándar, pero tiene un amplio soporte
DATE, TIMESTAMPfechas y horasescribe los literales como '2026-01-05'
BOOLEANverdadero o falsoMySQL lo trata como TINYINT(1)

Las restricciones incluyen PRIMARY KEY (identificador único de fila), NOT NULL, UNIQUE, CHECK (condition) y FOREIGN KEY / REFERENCES (el valor debe existir en otra tabla). Las cadenas usan comillas simples; las comillas dobles son para identificadores en SQL estándar.

SELECT: filtrar, ordenar y limitar

SELECT lee datos. WHERE filtra filas, ORDER BY las ordena y LIMIT (o el estándar FETCH FIRST n ROWS ONLY) restringe cuántas se devuelven.

SELECT name, city
FROM customers
WHERE city = 'Oslo'
ORDER BY name;
-- Ann | Oslo
-- Cy  | Oslo
SELECT id, amount,
       CASE WHEN amount >= 40 THEN 'large'
            WHEN amount >= 20 THEN 'medium'
            ELSE 'small' END AS size
FROM orders
WHERE amount BETWEEN 10 AND 50
ORDER BY amount DESC
LIMIT 2;
-- 2 | 45.50 | large
-- 1 | 30.00 | medium
SELECT name FROM customers WHERE city IS NULL;   -- not: city = NULL
SELECT name FROM customers WHERE name LIKE 'A%'; -- Ann

JOIN: combinar tablas

Un join une las filas de dos tablas mediante una condición, normalmente una clave foránea. INNER JOIN (o simplemente JOIN) conserva solo las filas que coinciden; LEFT JOIN conserva todas las filas de la tabla izquierda y rellena con NULL las columnas que faltan.

SELECT c.name, o.amount
FROM customers AS c
JOIN orders AS o ON o.customer_id = c.id
ORDER BY o.amount DESC;
-- Ann | 45.50
-- Ann | 30.00
-- Bo  | 12.00
SELECT c.name, o.id AS order_id
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
WHERE o.id IS NULL;        -- customers with no orders
-- Cy | NULL
JoinDevuelve
INNER JOINfilas que coinciden en ambas tablas
LEFT JOINtodas las filas de la izquierda, más las coincidencias de la derecha o NULL
RIGHT JOINtodas las filas de la derecha, más las coincidencias de la izquierda o NULL
FULL OUTER JOINtodas las filas de ambos lados; MySQL no lo admite
CROSS JOINtodas las combinaciones de filas (un producto cartesiano)

GROUP BY y funciones de agregación

Las funciones de agregación como COUNT, SUM, AVG, MIN y MAX resumen muchas filas en una. GROUP BY genera una fila de resultado por grupo, y HAVING filtra los grupos después de la agregación, mientras que WHERE filtra las filas antes de ella.

SELECT c.name,
       COUNT(o.id)               AS orders,
       COALESCE(SUM(o.amount), 0) AS total
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
GROUP BY c.id, c.name
ORDER BY total DESC;
-- Ann | 2 | 75.50
-- Bo  | 1 | 12.00
-- Cy  | 0 | 0
SELECT city, COUNT(*) AS n
FROM customers
GROUP BY city
HAVING COUNT(*) > 1;
-- Oslo | 2

COUNT(*) cuenta filas, mientras que COUNT(column) cuenta solo los valores no nulos, por eso Cy obtiene 0 pedidos en el ejemplo anterior. COALESCE devuelve su primer argumento no nulo.

Subconsultas, CTE y funciones de ventana

Una subconsulta es una consulta dentro de otra consulta. Una expresión de tabla común (CTE), escrita con WITH, da nombre a una subconsulta y hace legibles las consultas largas. Las funciones de ventana como ROW_NUMBER, RANK y SUM(...) OVER calculan valores sobre filas relacionadas sin colapsarlas en grupos.

SELECT name FROM customers
WHERE id IN (SELECT customer_id FROM orders WHERE amount > 20);
-- Ann
WITH totals AS (
  SELECT customer_id, SUM(amount) AS total
  FROM orders
  GROUP BY customer_id
)
SELECT c.name, t.total,
       RANK() OVER (ORDER BY t.total DESC) AS rnk
FROM totals AS t
JOIN customers AS c ON c.id = t.customer_id;
-- Ann | 75.50 | 1
-- Bo  | 12.00 | 2

Las CTE y las funciones de ventana están disponibles en PostgreSQL, en SQLite 3.25 y posteriores, y en MySQL 8.0 y posteriores.

Modificar datos: INSERT, UPDATE, DELETE y transacciones

UPDATE y DELETE afectan a todas las filas que cumplen la cláusula WHERE. Una transacción agrupa varias instrucciones para que todas se completen o todas fallen juntas.

UPDATE customers SET city = 'Paris' WHERE id = 2;
DELETE FROM orders WHERE amount < 15;
BEGIN;
UPDATE orders SET amount = amount - 10 WHERE id = 1;
UPDATE orders SET amount = amount + 10 WHERE id = 2;
COMMIT;                    -- or ROLLBACK; to undo both
SELECT id, amount FROM orders;
-- 1 | 20.00
-- 2 | 55.50

Diferencias entre PostgreSQL, MySQL y SQLite

El núcleo de SQL es portable, pero cada motor difiere en los detalles. Estas son las diferencias que los principiantes encuentran primero.

CaracterísticaPostgreSQLMySQLSQLite
ID autoincrementalGENERATED ALWAYS AS IDENTITY o SERIALAUTO_INCREMENTINTEGER PRIMARY KEY
Entrecomillado de nombres"name"acentos graves alrededor del nombre"name"
Limitar filasLIMIT n o FETCH FIRST n ROWS ONLYLIMIT nLIMIT n
Concatenación de cadenasa || bCONCAT(a, b)a || b
Booleanostipo BOOLEAN realTINYINT(1)se guardan como 0 y 1
Tipadoestrictoestricto en el modo estricto por defectoflexible, salvo que la tabla se declare STRICT
UpsertON CONFLICT ... DO UPDATEON DUPLICATE KEY UPDATEON CONFLICT ... DO UPDATE

Otras diferencias incluyen las funciones de fecha (NOW() en PostgreSQL y MySQL, datetime('now') en SQLite), la distinción de mayúsculas en las comparaciones de cadenas y la compatibilidad con el full outer join, del que carece MySQL.

Errores comunes y siguientes pasos

  • Construir consultas concatenando la entrada del usuario, lo que permite la inyección SQL. Usa siempre consultas parametrizadas (marcadores como ? o $1) desde tu lenguaje de programación.
  • Seleccionar en una consulta agrupada una columna que no está en GROUP BY ni dentro de una función de agregación.
  • Usar FLOAT para dinero en lugar de DECIMAL.
  • Olvidar los índices en las columnas que se usan en joins y filtros; CREATE INDEX idx_orders_customer ON orders(customer_id); y EXPLAIN ayudan en esto.
  • Suponer que las filas se devuelven en un orden fijo sin ORDER BY.

Para seguir estudiando, lee los manuales oficiales: el tutorial de PostgreSQL, el MySQL Reference Manual y la referencia del lenguaje SQL de SQLite. Practica con un conjunto de datos real escribiendo preguntas en lenguaje natural y convirtiendo cada una en una consulta.

Preguntas frecuentes

¿Es SQL un lenguaje de programación?

SQL es un lenguaje de consulta declarativo: describes el resultado que quieres en lugar de los pasos para calcularlo. Las extensiones de cada fabricante, como PL/pgSQL y T-SQL, añaden variables, bucles y procedimientos.

¿Con qué base de datos debería empezar un principiante?

SQLite no necesita servidor y es ideal para aprender. PostgreSQL es una gran opción para aprender SQL conforme al estándar en aplicaciones reales, y MySQL es habitual en el alojamiento web.

¿Cuál es la diferencia entre WHERE y HAVING?

WHERE filtra filas individuales antes de agrupar, y HAVING filtra grupos después de calcular las funciones de agregación.

¿Cuál es la diferencia entre INNER JOIN y LEFT JOIN?

INNER JOIN devuelve solo las filas que tienen coincidencia en ambas tablas. LEFT JOIN devuelve todas las filas de la tabla izquierda y rellena con NULL las columnas de la tabla derecha cuando no hay coincidencia.

¿Cómo evito la inyección SQL?

Nunca insertes la entrada del usuario en el texto SQL. Usa consultas parametrizadas o sentencias preparadas, en las que la base de datos recibe la consulta y los valores por separado.

Todos los tutoriales de programación