En esta página

Configurar PostgreSQL 18

12 min lectura TextoCap. 1 — Fundamentos de bases de datos

Configurar PostgreSQL 18

Antes de escribir consultas SQL reales, necesitas tener PostgreSQL funcionando en tu máquina. En esta lección instalaremos PostgreSQL 18, exploraremos las dos herramientas principales para interactuar con él (pgAdmin y psql), y crearemos nuestra primera base de datos con tablas bien tipadas.

Instalación de PostgreSQL 18

En macOS

La forma más sencilla en macOS es usando Homebrew:

# Instalar Homebrew si no lo tienes
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# Instalar PostgreSQL 18
brew install postgresql@18

# Agregar al PATH (añade esto a ~/.zshrc o ~/.bashrc)
export PATH="/opt/homebrew/opt/postgresql@18/bin:$PATH"

# Iniciar el servicio
brew services start postgresql@18

# Verificar que está corriendo
pg_isready

También puedes usar Postgres.app (postgresapp.com), que ofrece una interfaz gráfica simple y múltiples versiones de PostgreSQL.

En Ubuntu / Debian

# Agregar el repositorio oficial de PostgreSQL
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

sudo apt-get update
sudo apt-get -y install postgresql-18 postgresql-client-18

# Iniciar el servicio
sudo systemctl start postgresql
sudo systemctl enable postgresql

# Verificar estado
sudo systemctl status postgresql

En Windows

  1. Descarga el instalador desde postgresql.org/download/windows
  2. Ejecuta el instalador como administrador
  3. Elige los componentes: PostgreSQL Server, pgAdmin 4, Command Line Tools
  4. Define una contraseña para el usuario postgres (¡guárdala!)
  5. Puerto por defecto: 5432

Con Docker (recomendado para desarrollo)

# Ejecutar PostgreSQL 18 en contenedor
docker run --name pg18-dev \
  -e POSTGRES_PASSWORD=miclave_segura \
  -e POSTGRES_DB=mi_base \
  -p 5432:5432 \
  -v pgdata:/var/lib/postgresql/data \
  -d postgres:18

# Conectarse al contenedor
docker exec -it pg18-dev psql -U postgres -d mi_base

# Detener e iniciar
docker stop pg18-dev
docker start pg18-dev

La CLI psql

psql es la interfaz de línea de comandos oficial de PostgreSQL. Es tremendamente poderosa y es la herramienta que los profesionales usan en producción.

# Conectarse como superusuario
psql -U postgres

# Conectarse a una base de datos específica
psql -U postgres -d mi_base

# Conectarse a un servidor remoto
psql -h mi-servidor.com -p 5432 -U mi_usuario -d mi_base

# Con URL de conexión (formato recomendado)
psql postgresql://mi_usuario:miclave@localhost:5432/mi_base

Comandos meta de psql

Dentro de psql, los comandos que empiezan con \ son comandos del cliente, no SQL:

-- Listar bases de datos
\l

-- Conectarse a otra base de datos
\c nombre_base

-- Listar tablas del esquema actual
\dt

-- Listar tablas de todos los esquemas
\dt *.*

-- Describir la estructura de una tabla
\d nombre_tabla

-- Listar funciones
\df

-- Ver historial de comandos
\s

-- Ejecutar un archivo SQL
\i /ruta/al/archivo.sql

-- Activar visualización expandida (útil para filas anchas)
\x

-- Salir de psql
\q

pgAdmin 4

pgAdmin es la interfaz gráfica oficial de PostgreSQL. Ofrece:

  • Explorador de objetos (bases de datos, tablas, funciones, usuarios)
  • Editor de consultas con autocompletado
  • Visualizador de datos con filtros
  • Herramienta de backups y restauración
  • Monitor de rendimiento y actividad

Tras instalar pgAdmin, conéctate creando un nuevo servidor:

  • Nombre: Local Dev
  • Host: localhost
  • Puerto: 5432
  • Usuario: postgres
  • Contraseña: la que definiste en la instalación

Crear nuestra primera base de datos

-- Conectado como postgres, crear un usuario de aplicación
CREATE USER dev_user WITH PASSWORD 'dev_password_2024';

-- Crear la base de datos
CREATE DATABASE aprende_sql
  WITH
  OWNER = dev_user
  ENCODING = 'UTF8'
  LC_COLLATE = 'es_ES.UTF-8'
  LC_CTYPE = 'es_ES.UTF-8'
  TEMPLATE = template0
  CONNECTION LIMIT = 100;

-- Dar permisos
GRANT ALL PRIVILEGES ON DATABASE aprende_sql TO dev_user;

-- Conectarse a la nueva base de datos
\c aprende_sql dev_user

Tipos de datos en PostgreSQL 18

Los tipos de datos son fundamentales: definen qué valores puede contener cada columna y cuánto espacio ocupa en disco. PostgreSQL ofrece un sistema de tipos extraordinariamente rico.

Tipos numéricos

-- Enteros
SMALLINT      -- 2 bytes, -32.768 a 32.767
INTEGER       -- 4 bytes, -2.147 millones a 2.147 millones (el más común)
BIGINT        -- 8 bytes, ±9.2 × 10^18 (para IDs grandes o contadores)

-- Autoincrement (alias para INTEGER/BIGINT con secuencia)
SERIAL        -- = INTEGER + SEQUENCE automática
BIGSERIAL     -- = BIGINT + SEQUENCE automática

-- Decimales de precisión exacta (¡usa este para dinero!)
NUMERIC(10,2) -- 10 dígitos total, 2 decimales. Ej: 12345678.99
DECIMAL(10,2) -- Sinónimo de NUMERIC

-- Punto flotante (NO para dinero — tiene errores de redondeo)
REAL          -- 4 bytes, ~6 dígitos de precisión
DOUBLE PRECISION -- 8 bytes, ~15 dígitos de precisión

Tipos de texto

CHAR(n)       -- Cadena de longitud FIJA. Rellena con espacios. Casi nunca se usa.
VARCHAR(n)    -- Cadena de longitud VARIABLE con límite máximo n
TEXT          -- Cadena de longitud ilimitada (sin penalización de rendimiento vs VARCHAR)

-- En PostgreSQL, TEXT y VARCHAR tienen el mismo rendimiento.
-- Usa VARCHAR(n) cuando quieras imponer un límite de negocio,
-- TEXT cuando la longitud sea indefinida.

Tipos booleanos y fecha/hora

BOOLEAN       -- true / false / null
              -- Acepta: true, false, 'yes', 'no', '1', '0', 'on', 'off'

DATE          -- Solo fecha: '2024-12-25'
TIME          -- Solo hora: '14:30:00'
TIMESTAMP     -- Fecha y hora sin zona horaria: '2024-12-25 14:30:00'
TIMESTAMPTZ   -- Fecha y hora CON zona horaria (RECOMENDADO para producción)
INTERVAL      -- Período de tiempo: '2 hours', '3 days 4 hours'

[!warning] Usa siempre TIMESTAMPTZ (timestamp with time zone) en producción. Almacena el instante absoluto en UTC y lo convierte a la zona horaria del cliente automáticamente. Si usas TIMESTAMP sin zona, tendrás dolores de cabeza cuando tu aplicación sirva a usuarios en diferentes países o cuando el servidor cambie de zona horaria.

UUID

-- UUID: identificador único de 128 bits
-- Ideal para claves primarias en sistemas distribuidos
UUID          -- Almacena '550e8400-e29b-41d4-a716-446655440000'

-- Activar extensión pgcrypto para generar UUIDs v4
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- O usar la función nativa de PostgreSQL 13+
SELECT gen_random_uuid();  -- Disponible sin extensión en PG 13+

JSONB — el tipo estrella de PostgreSQL

-- JSON: almacena texto JSON (valida sintaxis pero no hace parsing)
-- JSONB: almacena JSON en formato binario descompuesto (RECOMENDADO)
-- JSONB soporta índices GIN, es más rápido para consultas, ocupa similar espacio

JSON          -- Preserva formato original, sin índices eficientes
JSONB         -- Binario, indexable, mejor rendimiento en consultas

Creando tablas reales con tipos bien elegidos

-- Habilitamos extensiones necesarias
CREATE EXTENSION IF NOT EXISTS pgcrypto;

-- Tabla de usuarios con tipos apropiados
CREATE TABLE usuarios (
  id            UUID          PRIMARY KEY DEFAULT gen_random_uuid(),
  email         VARCHAR(255)  NOT NULL UNIQUE,
  nombre        VARCHAR(100)  NOT NULL,
  apellido      VARCHAR(100),
  edad          SMALLINT      CHECK (edad >= 0 AND edad <= 150),
  activo        BOOLEAN       NOT NULL DEFAULT true,
  metadata      JSONB,        -- Datos adicionales flexibles
  creado_en     TIMESTAMPTZ   NOT NULL DEFAULT NOW(),
  actualizado_en TIMESTAMPTZ  NOT NULL DEFAULT NOW()
);

-- Tabla de productos con decimales correctos para precios
CREATE TABLE productos (
  id            SERIAL        PRIMARY KEY,
  sku           VARCHAR(50)   NOT NULL UNIQUE,
  nombre        VARCHAR(200)  NOT NULL,
  descripcion   TEXT,
  precio        NUMERIC(12,2) NOT NULL CHECK (precio >= 0),
  peso_kg       NUMERIC(8,3),           -- 3 decimales para kg
  atributos     JSONB,                  -- Color, talla, material, etc.
  disponible    BOOLEAN       NOT NULL DEFAULT true,
  creado_en     TIMESTAMPTZ   NOT NULL DEFAULT NOW()
);

-- Insertar datos de prueba
INSERT INTO usuarios (email, nombre, apellido, metadata)
VALUES
  ('[email protected]', 'Ana', 'García', '{"plan": "premium", "ciudad": "Madrid"}'),
  ('[email protected]', 'Luis', 'Martínez', '{"plan": "free", "ciudad": "Barcelona"}');

INSERT INTO productos (sku, nombre, descripcion, precio, peso_kg, atributos)
VALUES
  ('LAP-001', 'Laptop Pro 15"', 'Laptop profesional con chip M3', 1299.99, 1.850,
   '{"color": "gris espacial", "ram": "16GB", "almacenamiento": "512GB"}'),
  ('MOU-001', 'Mouse Inalámbrico', 'Mouse ergonómico Bluetooth', 49.99, 0.095,
   '{"color": "negro", "dpi": 1600, "bateria": "AA"}');

-- Consultar con operadores JSONB
SELECT nombre, metadata->>'ciudad' AS ciudad
FROM usuarios
WHERE metadata->>'plan' = 'premium';

SELECT nombre, atributos->>'color' AS color, precio
FROM productos
WHERE (atributos->>'ram') = '16GB';

Verificar la instalación

-- Verificar versión
SELECT version();

-- Ver parámetros de configuración importantes
SHOW max_connections;
SHOW shared_buffers;
SHOW work_mem;
SHOW timezone;

-- Ver las bases de datos
SELECT datname, pg_size_pretty(pg_database_size(datname)) AS tamaño
FROM pg_database
ORDER BY pg_database_size(datname) DESC;

-- Ver las tablas del esquema actual con su tamaño
SELECT
  schemaname,
  tablename,
  pg_size_pretty(pg_total_relation_size(schemaname || '.' || tablename)) AS tamaño
FROM pg_tables
WHERE schemaname = 'public'
ORDER BY pg_total_relation_size(schemaname || '.' || tablename) DESC;

[!tip] Configura postgresql.conf para desarrollo: el archivo de configuración principal de PostgreSQL está en /etc/postgresql/18/main/postgresql.conf (Linux) o /opt/homebrew/var/postgresql@18/postgresql.conf (macOS con Homebrew). Para desarrollo, ajusta shared_buffers = 256MB, work_mem = 16MB y log_min_duration_statement = 1000 (registra consultas lentas de más de 1 segundo) para detectar problemas de rendimiento desde el principio.

Resumen de tipos más usados

Tipo Cuándo usarlo
SERIAL / BIGSERIAL IDs autoincrement en tablas pequeñas/grandes
UUID IDs en sistemas distribuidos, APIs públicas
VARCHAR(n) Texto con longitud máxima conocida (email, nombre)
TEXT Texto largo sin límite (descripción, contenido)
NUMERIC(p,s) Dinero y valores donde la precisión es crítica
BOOLEAN Flags, estados binarios
TIMESTAMPTZ Fechas y horas en aplicaciones multiregión
DATE Solo fechas (cumpleaños, fechas de entrega)
JSONB Datos semiestructurados, metadatos variables

Con PostgreSQL instalado y nuestro primer esquema creado, estamos listos para lo más emocionante: escribir consultas. En la siguiente lección dominaremos SELECT, WHERE, ORDER BY y todas las cláusulas fundamentales para recuperar exactamente los datos que necesitamos.


nextSteps:

  • slug: select-where-y-order label: "Siguiente: SELECT, WHERE y ORDER BY"