Curso SQL · Northwind
Tema 4 de 60
Bloque 2 · La consulta PostgreSQL 17 northwind

SELECT y FROM

1. Qué es

SELECT es la única sentencia que pregunta. Todo lo demás en SQL crea, modifica o borra; SELECT solo lee.

Y tiene una propiedad que conviene entender desde el primer minuto: SELECT no devuelve la tabla, devuelve una tabla nueva. La original no se toca. Puedes equivocarte todas las veces que quieras.

Las dos piezas mínimas:

  • FROM — de dónde saco las filas.
  • SELECT — qué columnas quiero ver, y en qué forma.

Todo lo demás (filtrar, agrupar, ordenar) se le añade encima.

2. Sintaxis

SELECT columna1, columna2, expresión AS alias
FROM tabla;

Reglas que valen desde ya:

  • Las columnas van separadas por coma. La coma sobrante antes del FROM es el error de sintaxis más frecuente del mundo.
  • El ; cierra la sentencia. En psql es obligatorio; en DBeaver puedes ejecutar sin él, pero acostúmbrate.
  • Las mayúsculas en las palabras clave son convención, no obligación. select funciona igual. Se escriben en mayúscula para que el ojo separe el esqueleto de la consulta de los nombres de tus tablas.

3. Ejemplos sobre Northwind

La consulta mínima. Dos columnas de una tabla:

SELECT product_name, unit_price
FROM products
LIMIT 5;
         product_name         | unit_price
------------------------------+------------
 Chai                         |      18.00
 Chang                        |      19.00
 Aniseed Syrup                |      10.00
 Chef Anton's Cajun Seasoning |      22.00
 Chef Anton's Gumbo Mix       |      21.35

LIMIT 5 corta la salida a 5 filas. Se ve en detalle en ordenar-y-limitar; aquí lo uso solo para que los ejemplos quepan en pantalla.

Renombrar con AS. El alias cambia el título de la columna en el resultado, no en la tabla:

SELECT product_name AS producto,
       unit_price   AS precio_unitario
FROM products
LIMIT 5;
           producto           | precio_unitario
------------------------------+-----------------
 Chai                         |           18.00
 Chang                        |           19.00

AS es opcional (unit_price precio_unitario funciona), pero escríbelo siempre. Sin él, una coma olvidada convierte dos columnas en una sola con alias, en silencio y sin error.

El SELECT calcula. No estás limitado a las columnas que existen — puedes crear columnas nuevas:

SELECT product_name,
       unit_price,
       units_in_stock,
       unit_price * units_in_stock AS valor_en_stock
FROM products
LIMIT 5;
         product_name         | unit_price | units_in_stock | valor_en_stock
------------------------------+------------+----------------+----------------
 Chai                         |      18.00 |             39 |         702.00
 Chang                        |      19.00 |             17 |         323.00
 Aniseed Syrup                |      10.00 |             13 |         130.00
 Chef Anton's Cajun Seasoning |      22.00 |             53 |        1166.00
 Chef Anton's Gumbo Mix       |      21.35 |              0 |           0.00

valor_en_stock no existe en ninguna parte de la base. Se calcula al vuelo, fila por fila. Eso es el 80% del trabajo analítico: columnas que no estaban.

Concatenar texto con ||:

SELECT first_name || ' ' || last_name AS empleado,
       title
FROM employees
LIMIT 5;
     empleado     |         title
------------------+-----------------------
 Nancy Davolio    | Sales Representative
 Andrew Fuller    | Vice President, Sales
 Janet Leverling  | Sales Representative

FROM es opcional. Si no lees ninguna tabla, no hace falta:

SELECT 2 + 2 AS resultado, current_date AS hoy;
 resultado |    hoy
-----------+------------
         4 | 2026-08-20

Esto es más útil de lo que parece: es la forma de probar una función sin arrastrar una tabla detrás.

Alias de tabla. Se le pone un nombre corto a la tabla y se prefijan las columnas:

SELECT p.product_name, p.unit_price
FROM products AS p
LIMIT 3;

Con una sola tabla es innecesario. En cuanto haya dos, deja de serlo — ver inner-join.

Sobre SELECT *

SELECT * FROM products devuelve todas las columnas. Es cómodo para asomarse una vez, y mala costumbre en todo lo demás:

  1. Traes datos que no necesitas — más red, más memoria, más lento.
  2. Si mañana alguien añade una columna a la tabla, tu consulta cambia de forma sin que tú la toques. Todo lo que dependa de ella se rompe.
  3. No documenta nada. Quien lea tu consulta dentro de seis meses no sabrá qué esperabas.

Regla: * para explorar, nunca para producir.

4. Errores comunes

  1. Coma sobrante antes del FROM. ERROR: syntax error at or near "FROM" Cuenta las comas: deben ser una menos que las columnas.

  2. Usar el alias en el WHERE. Esto falla: sql SELECT product_name, unit_price * 1.18 AS con_igv FROM products WHERE con_igv > 20; ERROR: column "con_igv" does not exist No es un capricho: cuando se evalúa el WHERE, el SELECT todavía no ha ocurrido. El porqué completo está en orden-logico-de-ejecucion, el tema siguiente.

  3. Comillas dobles donde no van. En PostgreSQL, "algo" significa identificador exacto, respeta mayúsculas: sql SELECT "Product_Name" FROM products; ERROR: column "Product_Name" does not exist Sin comillas, PostgreSQL pasa todo a minúsculas y encuentra la columna. Con comillas, busca literalmente Product_Name, que no existe.

  4. Comillas simples para nombres de columna. 'product_name' no es la columna: es el texto product_name, repetido en todas las filas. No da error, que es lo peligroso. Simples = texto. Dobles = identificador.

  5. SELECT * en un informe que alguien va a mantener. Ver arriba.

5. Diferencias con SQL Server

PostgreSQL SQL Server
Concatenar || + (o CONCAT)
Identificador con espacios "Mi columna" [Mi columna]
Limitar filas LIMIT 5 TOP 5
Fecha de hoy current_date GETDATE()

La primera duele: en SQL Server 'a' + 'b' concatena; en PostgreSQL, ||. Y + sobre dos textos en PostgreSQL da error de tipo, no un resultado raro — que al menos avisa.

6. Ejercicios

  1. Lista el nombre y el país de los proveedores, con las columnas tituladas proveedor y pais.
  2. Muestra el nombre de cada producto y su precio con 18% de IGV añadido, en una columna llamada precio_con_igv.
  3. Devuelve una sola columna llamada empleado con el formato Apellido, Nombre.
  4. Averigua cuántas columnas devuelve SELECT * FROM orders — sin contarlas a ojo.
  5. Devuelve el nombre y la ciudad de los clientes con los títulos exactos Nombre de la empresa y Ciudad, con espacios y mayúsculas.

7. Pregunta de negocio

Finanzas quiere saber cuánto dinero hay parado en el almacén: el valor total del inventario producto por producto, del más caro al más barato.

No hace falta ninguna función que no hayas visto. Sí hace falta decidir qué es "valor".

SolucionesResuélvelos antes de abrir

1.

SELECT company_name AS proveedor, country AS pais
FROM suppliers;
             proveedor              | pais
------------------------------------+-------
 Exotic Liquids                     | UK
 New Orleans Cajun Delights         | USA
 Grandma Kelly's Homestead          | USA
 Tokyo Traders                      | Japan
 Cooperativa de Quesos 'Las Cabras' | Spain

29 filas en total.

2.

SELECT product_name, unit_price, unit_price * 1.18 AS precio_con_igv
FROM products;
         product_name         | unit_price | precio_con_igv
------------------------------+------------+----------------
 Chai                         |      18.00 |        21.2400
 Chef Anton's Gumbo Mix       |      21.35 |        25.1930

Fíjate en los 4 decimales: numeric(10,2) * 1.18 no devuelve numeric(10,2), devuelve la precisión que hace falta para no perder nada. Redondear es una decisión tuya, no del motor — ver funciones-dentro-del-select.

3.

SELECT last_name || ', ' || first_name AS empleado
FROM employees;
     empleado
-------------------
 Davolio, Nancy
 Fuller, Andrew
 Leverling, Janet

4.

SELECT count(*) FROM information_schema.columns WHERE table_name = 'orders';

Devuelve 14. La respuesta a ojo con \d orders vale igual; la consulta vale cuando la tabla tiene 200 columnas.

5.

SELECT company_name AS "Nombre de la empresa",
       city         AS "Ciudad"
FROM customers;
        Nombre de la empresa        |   Ciudad
------------------------------------+-------------
 Alfreds Futterkiste                | Berlin
 Ana Trujillo Emparedados y helados | México D.F.

Este es el único caso donde las comillas dobles se usan a propósito. Un alias con espacios o mayúsculas las necesita. Un alias normal, no.

Pregunta de negocio.

SELECT product_name,
       unit_price,
       units_in_stock,
       unit_price * units_in_stock AS valor_inventario
FROM products
ORDER BY valor_inventario DESC;
       product_name        | unit_price | units_in_stock | valor_inventario
---------------------------+------------+----------------+------------------
 Côte de Blaye             |     263.50 |             17 |          4479.50
 Raclette Courdavault      |      55.00 |             79 |          4345.00
 Queso Manchego La Pastora |      38.00 |             86 |          3268.00
 Sir Rodney's Marmalade    |      81.00 |             40 |          3240.00
 Sirop d'érable            |      28.50 |            113 |          3220.50

Dos cosas que este ejercicio enseña de verdad:

  • ORDER BY sí acepta el alias (valor_inventario), aunque WHERE no. No es incoherencia: ORDER BY se ejecuta después del SELECT. Otra vez, orden-logico-de-ejecucion.
  • "Valor" es ambiguo y hay que preguntarlo. unit_price es el precio de venta. El valor contable de un inventario normalmente es el de coste, que Northwind no guarda. Lo que has calculado es cuánto facturarías si lo vendieras todo, que no es lo mismo. Decirlo al entregar el dato es lo que separa a alguien que ejecuta SQL de alguien que analiza.