Hola! Aquí es donde se atasca la gente
En el capítulo 1 escribiste un SELECT y salió. Pero en tu trabajo la base no está en un archivo al lado del cuaderno: está en un servidor, con un usuario, una contraseña y un puerto 🔐
Y este paso, que ningún curso explica bien, es donde muchas personas se quedan. Vamos por partes.
Qué es un cliente
Un cliente es el programa donde escribes tus consultas y ves los resultados. La base vive en el servidor; el cliente es tu ventana a ella.
| Motor | Cliente oficial | Nota |
|---|---|---|
| PostgreSQL | pgAdmin, o psql en terminal | psql es feo y es lo que usan los que saben |
| MySQL | MySQL Workbench | También sirve phpMyAdmin si es una web |
| SQL Server | SQL Server Management Studio (SSMS) | Solo Windows. Azure Data Studio es la alternativa multiplataforma |
| SQLite | DB Browser for SQLite | Gratis, ligero, abre el archivo y ya |
Y el que te recomiendo de verdad: DBeaver. Es gratis, funciona con los cuatro (y con veinte más), y así aprendes una sola interfaz para toda tu carrera. Yo lo tengo abierto todo el día 💜
La cadena de conexión
Para conectarte hacen falta cinco datos, siempre los mismos: servidor, puerto, base, usuario y contraseña. Lo que cambia es el puerto por defecto y cómo se escribe todo junto.
La cadena de conexión y el puerto de fábrica
| PostgreSQL | postgresql://usuario:clave@servidor:5432/mi_base |
| MySQL | mysql://usuario:clave@servidor:3306/mi_base |
| SQL Server | Server=servidor,1433;Database=mi_base;User Id=usuario;Password=clave; |
| SQLite | ruta/a/tienda.db (no hay servidor, usuario ni puerto) |
SQLite es el raro y por una buena razón: no tiene servidor. La base es el archivo, así que conectarte es abrirlo.
Tres avisos que te van a ahorrar una tarde:
- 🔑 La contraseña nunca va escrita en el código. Va en una variable de entorno o en un gestor de secretos. Si subes una a un repositorio, considérala quemada y cámbiala.
- 🌐 Si no conecta, casi siempre es red y no clave. Un firewall, una VPN que falta o el servidor que no acepta conexiones de fuera.
- 👤 Pide un usuario de solo lectura. Para analizar no necesitas poder borrar nada, y así no puedes romper nada por accidente.
Dónde viven los datos que vas a consultar
Un detalle que ahorra un malentendido incómodo el primer mes de trabajo: cuando pides acceso a "la base de datos" y te dan otra cosa, no es desconfianza.
La base donde se registran las ventas mientras ocurren se llama transaccional, y está afinada para escribir rapidísimo, no para que tú le hagas preguntas pesadas. Una consulta tuya con tres JOIN a las once de la mañana puede poner lenta la caja de la tienda 😬
Por eso casi todas las empresas tienen una copia aparte:
- 🏭 El data warehouse es esa copia ya ordenada en tablas, pensada justo para que la interrogues. El 90% del SQL que escribas en tu vida laboral va contra uno de estos.
- 🌊 El data lake es la copia cruda, tal como llegó, sin ordenar. Sirve para guardar todo por si acaso, y para trabajar ahí hace falta más herramienta que SQL.
- 🔁 Y el proceso que mueve los datos de un sitio a otro y los limpia por el camino se llama ETL: extraer, transformar y cargar. Suele correr de madrugada, y por eso el reporte de hoy a veces trae los datos de ayer.
Todo eso es trabajo de ingeniería de datos y no hace falta para este libro. Solo quiero que la palabra no te suene nueva el día que alguien la diga en una reunión 💛
Lo primero al entrar a una base que no conoces
Te dan acceso y te encuentras con doscientas tablas con nombres como
TB_MOV_CAB. Esto es lo que hago yo, en este orden 🔍
1. Qué tablas hay
SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name;
name ----------- clientes detalle direcciones pedidos productos
Listar las tablas
| PostgreSQL | SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'; |
| MySQL | SHOW TABLES; |
| SQL Server | SELECT name FROM sys.tables; |
| SQLite | SELECT name FROM sqlite_master WHERE type = 'table'; |
PostgreSQL, MySQL y SQL Server tienen information_schema.tables, que es lo estándar. Si escribes esa, la misma consulta te sirve en los tres.
2. Qué columnas tiene cada una
PRAGMA table_info(pedidos);
cid name type notnull dflt_value pk --- ---------- ------- ------- ---------- -- 0 id INTEGER 0 1 1 id_cliente INTEGER 0 0 2 fecha TEXT 0 0 3 canal TEXT 0 0 4 monto REAL 0 0
Ver las columnas de una tabla
| PostgreSQL | SELECT column_name, data_type FROM information_schema.columns WHERE table_name = 'pedidos'; |
| MySQL | DESCRIBE pedidos; |
| SQL Server | sp_help 'pedidos'; |
| SQLite | PRAGMA table_info(pedidos); |
El DESCRIBE de MySQL es el más cómodo y no existe en los otros. information_schema.columns vuelve a ser la forma que viaja.
Fíjate en la columna pk de la salida: dice que id es
la clave primaria, o sea lo que identifica a cada fila sin
repetirse. Eso lo vas a necesitar en el capítulo de los JOIN.
3. Cómo se relacionan
Los nombres ya te lo cuentan casi todo: pedidos.id_cliente
apunta a clientes.id. Esa es una clave foránea, el
hilo que une dos tablas.
PRAGMA foreign_key_list(detalle);
id seq table from to on_update on_delete match -- --- --------- ----------- -- --------- --------- ----- 0 0 productos id_producto id NO ACTION NO ACTION NONE 1 0 pedidos id_pedido id NO ACTION NO ACTION NONE
Ahí está el mapa de la base en dos líneas: detalle apunta a
productos y a pedidos. O sea que cada línea de detalle
es un producto dentro de un pedido 🌟
Ver las claves foráneas
| PostgreSQL | SELECT * FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'; |
| MySQL | SELECT * FROM information_schema.key_column_usage WHERE referenced_table_name IS NOT NULL; |
| SQL Server | SELECT * FROM sys.foreign_keys; |
| SQLite | PRAGMA foreign_key_list(detalle); |
Y un aviso sobre SQLite: por defecto NO obliga a que se cumplan. Están declaradas y no se revisan salvo que actives PRAGMA foreign_keys = ON. En los otros tres se cumplen siempre.
4. Cuánto pesa cada tabla y qué hay dentro
SELECT COUNT(*) AS pedidos,
MIN(fecha) AS desde,
MAX(fecha) AS hasta,
COUNT(DISTINCT id_cliente) AS clientes,
COUNT(DISTINCT canal) AS canales
FROM pedidos;
pedidos desde hasta clientes canales ------- ---------- ---------- -------- ------- 900 2025-01-01 2026-06-24 119 4
Esa consulta la escribo siempre y en cualquier motor funciona igual. En una línea te dice el tamaño, el periodo que cubre y cuánta variedad hay. Si el periodo no es el que esperabas, ya te ahorraste el análisis entero 💜
Y mira el detalle que suelta gratis: hay 120 clientes en la tabla pero solo 119 hicieron algún pedido. O sea que hay uno que se dio de alta y nunca compró. Eso, en un negocio de verdad, es una pregunta 🔍
Y para ver qué valores toma una columna:
SELECT canal, COUNT(*) AS pedidos FROM pedidos GROUP BY canal ORDER BY pedidos DESC;
canal pedidos ----------- ------- Web 234 WhatsApp 231 Marketplace 229 Tienda 206
Mirar antes de contar
Antes de sacar un solo número, mira filas de verdad. Diez filas te dicen más que cualquier documentación.
SELECT * FROM pedidos LIMIT 5;
id id_cliente fecha canal monto -- ---------- ---------- ----------- ------ 1 69 2025-05-30 Web 892.06 2 95 2025-06-03 Marketplace 731.09 3 63 2025-09-23 Tienda 407.39 4 114 2025-02-18 Tienda 358.23 5 67 2025-07-09 Web 844.94
Ahí ya se ve que la fecha viene como texto, que el monto es decimal y que
id_cliente es un número que apunta a otra tabla.
Ese SELECT * está bien para mirar y mal para
trabajar: en una tabla de cuarenta columnas y millones de filas, traes
todo para nada. Para explorar, perfecto; en una consulta que va a quedar
guardada, nombra las columnas.
Ejercicios
1. El esquema de clientes
Mira qué columnas tiene la tabla clientes.
PRAGMA table_info(clientes);
cid name type notnull dflt_value pk --- ---------- ------- ------- ---------- -- 0 id INTEGER 0 1 1 nombre TEXT 1 0 2 ciudad TEXT 0 0 3 segmento TEXT 0 0 4 fecha_alta TEXT 0 0
2. La ficha de productos
Saca cuántos productos hay, cuántas categorías, y el precio mínimo y máximo.
SELECT COUNT(*) AS productos,
COUNT(DISTINCT categoria) AS categorias,
MIN(precio) AS mas_barato,
MAX(precio) AS mas_caro
FROM productos;
productos categorias mas_barato mas_caro --------- ---------- ---------- -------- 40 5 4.01 89.35
3. Los valores de una columna
Lista los segmentos de cliente con cuántos hay de cada uno.
SELECT segmento, COUNT(*) AS clientes FROM clientes GROUP BY segmento ORDER BY clientes DESC;
segmento clientes ---------- -------- Horeca 36 Bodega 35 Minimarket 25 Mayorista 24
Treinta de cada uno, o sea que la base está balanceada a propósito. En datos reales esto casi nunca sale tan redondo, y cuando sale conviene preguntarse por qué 👀
4. El periodo de la base
Averigua desde cuándo y hasta cuándo hay pedidos, y cuántos días son.
SELECT MIN(fecha) AS desde,
MAX(fecha) AS hasta,
CAST(julianday(MAX(fecha)) - julianday(MIN(fecha)) AS INTEGER) AS dias
FROM pedidos;
desde hasta dias ---------- ---------- ---- 2025-01-01 2026-06-24 539
Ese julianday es de SQLite. Aquí es donde más se separan los
cuatro motores, y lo vemos entero en el capítulo 5.
5. Escríbelo para los cuatro
Sin ejecutar: escribe "lista las tablas de la base" en los cuatro motores, y di cuál de las formas te serviría en tres de ellos.
-- PostgreSQL, MySQL y SQL Server: la forma estándar SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'; -- en MySQL, el nombre de tu base -- Los atajos de cada uno SHOW TABLES; -- MySQL SELECT name FROM sys.tables; -- SQL Server SELECT name FROM sqlite_master WHERE type = 'table'; -- SQLite, el único sin information_schema
La de information_schema te sirve en tres. SQLite es el que no la
tiene, y tiene sentido: es un archivo, no un servidor con catálogo.
6. La tabla que no existe
Consulta una tabla inventada y lee el error.
SELECT * FROM ventas LIMIT 3;
OperationalError: no such table: ventas
En PostgreSQL sería relation "ventas" does not exist, en MySQL
Table 'mi_base.ventas' doesn't exist y en SQL Server
Invalid object name 'ventas'. Cuando te pase, casi siempre es que
estás en otra base o en otro esquema del que crees 🙃
Lo que te llevas
- 🔌 Un cliente es tu ventana a la base. DBeaver te sirve para los cuatro.
- 🔑 La contraseña nunca en el código, y pide usuario de solo lectura.
- 🗺️ Al entrar a una base nueva: qué tablas hay, qué columnas, cómo se relacionan y cuánto pesan.
- 📖
information_schemaes la forma que viaja entre PostgreSQL, MySQL y SQL Server. - 👀 Mira diez filas de verdad antes de contar nada.
En el capítulo 3 empieza lo bueno: filtrar. Y ahí aparece la primera diferencia gorda entre motores, la de limitar filas.
Que tengas lindo día! 🌸