Referencia

Referencia de SQL

Comandos, sintaxis y notas breves — desde SELECT hasta las funciones de ventana, los índices y las transacciones. Abre un artículo para profundizar.

Fundamentos: SELECT y filtrado4

SELECT … FROM
Artículo
SELECT col1, col2 FROM table_name;

Elige columnas de una tabla.

Véase también:····
SELECT * FROM t
WHERE col = 5 AND status = 'active';

Filtra filas: =, <>, <, >, AND, OR, IN, BETWEEN, LIKE.

Véase también:····
ORDER BY
Artículo
SELECT * FROM t ORDER BY created_at DESC;

Ordena el resultado. ASC ascendente (por defecto), DESC descendente.

Véase también:····
SELECT * FROM t ORDER BY id LIMIT 10;

Limita el número de filas devueltas.

Véase también:····

Combinar tablas (JOIN)7

INNER JOIN
Artículo
SELECT * FROM a JOIN b ON a.id = b.a_id;

Solo las filas que tienen correspondencia en ambas tablas.

Véase también:·····
LEFT JOIN
Artículo
SELECT * FROM a LEFT JOIN b ON a.id = b.a_id;

Todas las filas de la tabla izquierda; NULL a la derecha si no hay correspondencia.

Véase también:·····
Aliases
Artículo
SELECT u.name
FROM users u
JOIN orders o ON o.user_id = u.id;

Nombres cortos para las tablas — obligatorios cuando las columnas comparten nombre.

Véase también:····
CROSS JOIN
Artículo
SELECT * FROM sizes CROSS JOIN colors;

Producto cartesiano — cada fila izquierda con cada fila derecha. Para generar todas las combinaciones.

Véase también:·····
FULL OUTER JOIN
Artículo
SELECT * FROM a FULL OUTER JOIN b ON a.id = b.a_id;

Todas las filas de ambas tablas; NULL donde no hay correspondencia. MySQL no tiene FULL JOIN — se emula con LEFT ∪ RIGHT.

Véase también:·····
Self-join
Artículo
SELECT e.name, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;

Una tabla unida consigo misma mediante alias — para jerarquías como «empleado → jefe».

Véase también:·····
Anti-join (LEFT JOIN + IS NULL)
Artículo
SELECT u.*
FROM users u
LEFT JOIN orders o ON o.user_id = u.id
WHERE o.id IS NULL;

Filas de la izquierda SIN correspondencia a la derecha — «usuarios sin pedidos». Alternativa a NOT EXISTS.

Véase también:·····

Agregación y agrupación30

SELECT COUNT(*), COUNT(email) FROM users;

Cuenta filas de un grupo. COUNT(*) — todas las filas, COUNT(col) — solo no NULL, COUNT(DISTINCT col) — valores únicos.

Véase también:···
SELECT SUM(amount) FROM orders;

Suma de valores numéricos de un grupo. Los NULL se ignoran. Devuelve NULL (no 0) si el grupo está vacío.

SELECT AVG(price) FROM products;

Media aritmética. Los NULL se excluyen del divisor. Convierte una columna entera a numeric o se truncan los decimales.

SELECT MIN(created_at) FROM orders;

Valor mínimo de un grupo. Funciona con números, fechas y cadenas. Los NULL se ignoran.

SELECT MAX(created_at) FROM orders;

Valor máximo de un grupo. Funciona con números, fechas y cadenas. Los NULL se ignoran.

GROUP BY
Artículo
SELECT user_id, COUNT(*) FROM orders GROUP BY user_id;

Agrupa filas. Toda columna de SELECT que no sea de agregación debe estar en GROUP BY.

Véase también:···
HAVING
Artículo
SELECT user_id, COUNT(*)
FROM orders
GROUP BY user_id
HAVING COUNT(*) > 5;

Filtra sobre agregados — como WHERE pero después de GROUP BY.

Véase también:···
DISTINCT
Artículo
SELECT DISTINCT country FROM users;

Elimina las filas duplicadas del resultado.

Véase también:····
COUNT(*) FILTERPostgreSQL
Artículo
COUNT(*) FILTER (WHERE type = 'view') AS views

Agregado condicional: COUNT/SUM solo sobre las filas que cumplen el WHERE. Sustituye tres consultas separadas por una sola.

Véase también:·····
STRING_AGGPostgreSQL
Artículo
STRING_AGG(name, ', ' ORDER BY created_at)

Concatena valores en una sola cadena con un separador. El ORDER BY interno fija el orden.

Véase también:··
ARRAY_AGGPostgreSQL
Artículo
ARRAY_AGG(amount ORDER BY created_at)

Reúne valores en un array. Útil cuando una fila de auditoría necesita todo el historial en una celda.

Véase también:··
GROUPING SETSPostgreSQL
Artículo
GROUP BY GROUPING SETS ((kind), (user_id), ())

Varios niveles de agrupación en una consulta — fila a fila: por kind, por user_id y un total general.

Véase también:···
ROLLUPPostgreSQL
Artículo
GROUP BY ROLLUP (DATE_TRUNC('month', ts))

El mismo nivel de agrupación más una fila de total general (una única fila NULL al final).

Véase también:···
PERCENTILE_CONTPostgreSQL
Artículo
PERCENTILE_CONT(0.5) WITHIN GROUP (ORDER BY amount)

Mediana / cuantil. Más resistente a los valores atípicos que AVG.

Véase también:···
UNNESTPostgreSQL
Artículo
SELECT tag FROM articles, UNNEST(tags) tag

Expande un array en filas — una fila por cada elemento del array.

Véase también:··
COUNT(DISTINCT)
Artículo
SELECT COUNT(DISTINCT user_id) FROM events;

Cuenta los valores distintos. Costoso en tablas grandes — usa APPROX_COUNT_DISTINCT / HLL cuando basta con una estimación.

Véase también:···
BOOL_AND / BOOL_OR
Artículo
SELECT BOOL_AND(active), BOOL_OR(is_admin) FROM users;

Agregados booleanos: BOOL_AND es true si TODAS las filas son true; BOOL_OR si al menos una lo es. Los NULL se ignoran.

Véase también:·
SELECT dept, EVERY(salary > 0) FROM emp GROUP BY dept;

El sinónimo estándar de SQL para BOOL_AND — true cuando la condición se cumple en todas las filas del grupo.

Véase también:·
STDDEV
Artículo
SELECT STDDEV_SAMP(amount), STDDEV_POP(amount) FROM orders;

Desviación estándar: _SAMP para una muestra (divisor n-1), _POP para toda la población (divisor n). STDDEV a secas equivale a STDDEV_SAMP.

Véase también:···
VARIANCE
Artículo
SELECT VAR_SAMP(amount), VAR_POP(amount) FROM orders;

Varianza — el cuadrado de la desviación estándar. _SAMP para muestra, _POP para población. VARIANCE a secas equivale a VAR_SAMP.

Véase también:···
MODE() WITHIN GROUPPostgreSQL
Artículo
SELECT MODE() WITHIN GROUP (ORDER BY status) FROM tickets;

La moda — el valor más frecuente del grupo. En caso de empate gana el primero según ORDER BY.

Véase también:···
PERCENTILE_DISC
Artículo
SELECT PERCENTILE_DISC(0.5) WITHIN GROUP (ORDER BY amount) FROM orders;

Percentil discreto — devuelve un valor que realmente existe en los datos, a diferencia de PERCENTILE_CONT que interpola.

Véase también:···
BIT_AND / BIT_OR
Artículo
SELECT BIT_OR(flags), BIT_AND(flags) FROM permissions;

Agregados a nivel de bits sobre una columna integer: BIT_OR reúne todos los bits activos, BIT_AND conserva los comunes a todas las filas. Para máscaras de banderas.

Véase también:·
JSON_AGG / JSONB_AGGPostgreSQL
Artículo
SELECT JSONB_AGG(t ORDER BY t.id) FROM tasks t;

Agrupa filas en un array JSON — útil para devolver datos anidados en una sola consulta. JSONB_AGG lo guarda como jsonb (más rápido, sin claves duplicadas).

Véase también:····
JSONB_OBJECT_AGGPostgreSQL
Artículo
SELECT JSONB_OBJECT_AGG(key, value) FROM settings;

Convierte pares clave-valor en un único objeto JSON. Ideal para transformar una tabla de ajustes en un mapa.

Véase también:····
SELECT CORR(price, sales) FROM products;

Coeficiente de correlación de Pearson entre dos columnas: de -1 a 1. Una medida de asociación lineal.

Véase también:···
REGR_SLOPE / REGR_INTERCEPT
Artículo
SELECT REGR_SLOPE(y, x), REGR_INTERCEPT(y, x) FROM points;

Pendiente e intersección de la recta de regresión de y sobre x — una tendencia en un solo agregado, sin paquetes estadísticos externos.

Véase también:···
REGR_R2
Artículo
SELECT REGR_R2(y, x) FROM points;

El coeficiente de determinación R² de la regresión de y sobre x: 0..1, qué tan bien la recta se ajusta a los datos.

Véase también:···
MAX(...) FILTER (pivot)PostgreSQL
Artículo
SELECT user_id,
  MAX(amount) FILTER (WHERE kind = 'deposit')  AS deposit,
  MAX(amount) FILTER (WHERE kind = 'withdraw') AS withdraw
FROM tx GROUP BY user_id;

Transforma filas en columnas (pivot): MAX/SUM con FILTER por categoría. Sustituye un montón de agregados CASE escritos a mano.

Véase también:···
SELECT region, product, SUM(amount)
FROM sales
GROUP BY CUBE (region, product);

Todas las combinaciones de agrupación a la vez: por region, por product, por ambos y un total general. Para informes de tabla cruzada.

Véase también:···

Subconsultas3

IN (subquery)
Artículo
SELECT * FROM users WHERE id IN (SELECT user_id FROM orders);

Comprueba la pertenencia a una lista generada por otra consulta.

Véase también:···
EXISTS
Artículo
SELECT * FROM users u
WHERE EXISTS (
  SELECT 1 FROM orders o WHERE o.user_id = u.id
);

Conserva la fila si la consulta interna encuentra al menos una fila coincidente.

Véase también:···
Scalar subquery
Artículo
SELECT
  name,
  (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS cnt
FROM users u;

Una subconsulta que devuelve un único valor — puede ir dentro de SELECT.

Véase también:···

Operaciones de conjuntos (UNION/INTERSECT)3

UNION / UNION ALL
Artículo
SELECT id FROM a
UNION ALL
SELECT id FROM b;

Apila los resultados de dos consultas (mismo número de columnas, tipos compatibles). UNION elimina duplicados, UNION ALL los conserva (y es más rápido).

Véase también:·
INTERSECT
Artículo
SELECT user_id FROM purchases
INTERSECT
SELECT user_id FROM refunds;

Filas presentes en AMBAS consultas. En MySQL — desde la versión 8.0.31.

Véase también:·
EXCEPT
Artículo
SELECT user_id FROM users
EXCEPT
SELECT user_id FROM banned;

Filas de la primera consulta que NO están en la segunda. En Oracle es MINUS.

Véase también:·

Funciones de ventana9

ROW_NUMBER
Artículo
SELECT
  name,
  ROW_NUMBER() OVER (ORDER BY score DESC) AS rn
FROM players;

Número secuencial único para cada fila dentro de la ventana.

Véase también:····
RANK / DENSE_RANK
Artículo
RANK() OVER (PARTITION BY dept ORDER BY salary DESC)

Rango con saltos (RANK) o sin saltos (DENSE_RANK) cuando hay empates.

Véase también:··
PARTITION BY
Artículo
SUM(amount) OVER (PARTITION BY user_id ORDER BY created_at)

Divide la ventana en grupos — el agregado se calcula por grupo.

Véase también:·
LAG / LEAD
Artículo
LAG(price, 1) OVER (ORDER BY date)

Valor de la fila anterior (LAG) o siguiente (LEAD) de la ventana.

Véase también:··
NTILE(4) OVER (ORDER BY score DESC)

Divide las filas en N grupos del mismo tamaño en orden. Con cantidades desiguales los grupos quedan 3-3-2-2 (los sobrantes van a los de número más bajo).

Véase también:·····
FIRST_VALUE / LAST_VALUE
Artículo
LAST_VALUE(score) OVER (
  PARTITION BY team_id ORDER BY score DESC
  ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)

Primer / último valor de la ventana. Para LAST_VALUE hay que ampliar el marco con ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING — si no, el marco por defecto recorta el borde derecho.

Véase también:··
PERCENT_RANK
Artículo
PERCENT_RANK() OVER (ORDER BY score DESC, player_id)

Rango percentil de 0 a 1. Una segunda columna de ordenación hace el resultado determinista cuando hay empates.

Véase también:··
NTH_VALUE
Artículo
NTH_VALUE(amount, 2) OVER (
  PARTITION BY customer_id ORDER BY amount DESC
  ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
)

El N-ésimo valor de la ventana. También requiere el marco ampliado.

Véase también:··
Window frames
Artículo
AVG(x) OVER (ORDER BY d ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)

Ventanas deslizantes: «los últimos 7 días incluidos», «media de 3 días», etc.

Véase también:····

CTE y recursión (WITH)5

WITH … AS
Artículo
WITH active AS (
  SELECT * FROM users WHERE status = 'active'
)
SELECT * FROM active WHERE country = 'RU';

Un resultado temporal con nombre — divide una consulta grande en pasos.

Véase también:··
Multiple CTEs
Artículo
WITH a AS (...), b AS (...)
SELECT * FROM a JOIN b ON ...;

Varios CTE separados por comas, se leen de arriba abajo.

Véase también:··
WITH RECURSIVE
Artículo
WITH RECURSIVE chain AS (
  SELECT id, manager_id FROM emp WHERE manager_id IS NULL
  UNION ALL
  SELECT e.id, e.manager_id FROM emp e JOIN chain c ON e.manager_id = c.id
)
SELECT * FROM chain;

Recorre una jerarquía: consulta de anclaje → UNION ALL → paso recursivo. Ideal para organigramas, grafos y cadenas.

Véase también:··
LATERAL
Artículo
FROM customers c
LEFT JOIN LATERAL (
  SELECT * FROM orders WHERE customer_id = c.id
  ORDER BY amount DESC LIMIT 2
) l ON true

La subconsulta ve las columnas de la fila externa. Ideal para «top-N por cada X». LEFT JOIN LATERAL … ON true conserva las filas externas sin coincidencia; la forma con coma las descarta en silencio.

Véase también:·····
generate_seriesPostgreSQL
Artículo
generate_series('2024-01-01'::date, '2024-01-15'::date, '1 day')

Genera un calendario / eje. Incluye ambos extremos. Truco habitual para «rellenar con cero los días que faltan».

Véase también:··

Modificación de datos (DML)10

INSERT
Artículo
INSERT INTO t (col1, col2) VALUES (1, 'a'), (2, 'b');

Agrega filas a una tabla.

Véase también:··
UPDATE
Artículo
UPDATE t SET col = 'x' WHERE id = 5;

Modifica filas existentes. Incluye siempre WHERE — si no, se actualizan TODAS las filas.

Véase también:··
DELETE
Artículo
DELETE FROM t WHERE id = 5;

Elimina filas. Incluye siempre WHERE.

Véase también:··
ON CONFLICT DO NOTHINGPostgreSQL
Artículo
INSERT INTO t (id) VALUES (1)
ON CONFLICT (id) DO NOTHING;

Inserción idempotente — al volver a ejecutarse omite sin avisar las filas que ya existen.

Véase también:··
ON CONFLICT DO UPDATEPostgreSQL
Artículo
INSERT INTO t (id, n) VALUES (1, 1)
ON CONFLICT (id) DO UPDATE
  SET n = t.n + EXCLUDED.n;

UPSERT: insertar o actualizar. EXCLUDED.col es el valor que intentamos insertar.

Véase también:··
MERGEPostgreSQL
Artículo
MERGE INTO t USING src ON t.id = src.id
WHEN MATCHED THEN UPDATE SET ...
WHEN NOT MATCHED THEN INSERT ...;

Postgres 15+ — alternativa a UPSERT con ramas MATCHED / NOT MATCHED y condiciones en cada una.

Véase también:··
RETURNINGPostgreSQL
Artículo
INSERT INTO t (name) VALUES ('a')
RETURNING id, name;

Devuelve las filas recién insertadas / actualizadas / eliminadas en la misma sentencia — sin un segundo viaje al servidor.

Véase también:·····
DELETE … USINGPostgreSQL
Artículo
DELETE FROM orders o
USING customers c
WHERE o.customer_id = c.id AND c.country = 'US';

DELETE al estilo JOIN — filtra por otra tabla sin una subconsulta.

Véase también:··
UPDATE … FROMPostgreSQL
Artículo
UPDATE customers c SET total = s.total
FROM (SELECT customer_id, SUM(amount) AS total FROM orders GROUP BY customer_id) s
WHERE c.id = s.customer_id;

UPDATE masivo impulsado por una subconsulta de agregación.

Véase también:··
CTE + DELETE … RETURNINGPostgreSQL
Artículo
WITH moved AS (
  DELETE FROM orders WHERE old RETURNING *
)
INSERT INTO archive SELECT * FROM moved;

Archivado atómico: mueve las filas en una sola sentencia, sin ventana de carrera entre DELETE e INSERT.

Véase también:··

Esquema (DDL)10

CREATE TABLE
Artículo
CREATE TABLE t (
  id INTEGER PRIMARY KEY,
  name VARCHAR(100) NOT NULL
);

Crea una tabla con columnas tipadas.

Véase también:···
ALTER TABLE
Artículo
ALTER TABLE t ADD COLUMN created_at TIMESTAMP;

Modifica una tabla existente.

Véase también:···
ALTER TABLE products
ADD CONSTRAINT price_positive CHECK (price > 0);

Rechaza valores no válidos a nivel de base de datos, no en el código.

Véase también:···
FK ON DELETE
Artículo
FOREIGN KEY (post_id) REFERENCES posts(id)
  ON DELETE CASCADE   -- or SET NULL / RESTRICT

Qué hacer con la fila hija cuando se elimina la padre: propagar en cascada, poner la clave foránea a NULL o bloquear.

Véase también:···
NOT VALID + VALIDATEPostgreSQL
Artículo
ALTER TABLE t
  ADD CONSTRAINT fk REFERENCES p(id) NOT VALID;
ALTER TABLE t VALIDATE CONSTRAINT fk;

Agrega una clave foránea a una tabla grande en producción sin un bloqueo pesado: NOT VALID es instantáneo, VALIDATE no bloquea a los escritores.

Véase también:···
GENERATED column
Artículo
total NUMERIC GENERATED ALWAYS AS (price * (1 + tax)) STORED

El valor de la columna se calcula automáticamente — la fórmula vive en un único lugar.

Véase también:···
Partial UNIQUEPostgreSQL
Artículo
CREATE UNIQUE INDEX u ON users (email)
WHERE deleted_at IS NULL;

Unicidad solo sobre las filas activas — para el soft-delete, de modo que los usuarios puedan registrarse de nuevo tras la eliminación.

Véase también:···
Range partitioningPostgreSQL
Artículo
CREATE TABLE logs (...) PARTITION BY RANGE (ts);
CREATE TABLE logs_2024 PARTITION OF logs
  FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');

Divide una tabla grande por rangos. Las particiones antiguas se eliminan en milisegundos.

Véase también:···
TRIGGERPostgreSQL
Artículo
CREATE TRIGGER touch BEFORE UPDATE ON notes
FOR EACH ROW EXECUTE FUNCTION touch_updated_at();

Lógica automática a nivel de base de datos — por ejemplo, actualizar updated_at sin tocar el código de la aplicación.

Véase también:···
MATERIALIZED VIEWPostgreSQL
Artículo
CREATE MATERIALIZED VIEW v AS SELECT ...;
REFRESH MATERIALIZED VIEW v;

Resultado cacheado de una consulta pesada. Se actualiza de forma programada con REFRESH.

Véase también:···

Cadenas y fechas9

LOWER / UPPER / LENGTH
Artículo
LOWER(name), UPPER(code), LENGTH(text)

Minúsculas, mayúsculas, longitud de la cadena.

CONCAT
Artículo
CONCAT(first_name, ' ', last_name)

Concatena cadenas de texto. PostgreSQL también admite el operador || (en MySQL, || es el OR lógico por defecto, no la concatenación).

Véase también:··
EXTRACT
Artículo
EXTRACT(YEAR FROM created_at), EXTRACT(MONTH FROM created_at)

Extrae una parte de una fecha — año, mes, día.

Véase también:···
DATE_TRUNCPostgreSQL
Artículo
DATE_TRUNC('month', created_at)

Trunca una marca de tiempo hacia abajo a un período (día/semana/mes). La herramienta básica para agrupar por tiempo.

Véase también:···
NOW / CURRENT_DATE + INTERVAL
Artículo
WHERE created_at >= NOW() - INTERVAL '7 days'

Instante actual (NOW()) / hoy (CURRENT_DATE) y aritmética con intervalos — «en los últimos 7 días».

Véase también:·
CAST / ::
Artículo
CAST(price AS INTEGER)   -- or price::int

Convierte un valor a otro tipo. CAST(x AS type) es estándar; x::type es la forma corta de PostgreSQL.

Véase también:·
TRIM / SUBSTRING / REPLACE
Artículo
TRIM(name), SUBSTRING(code FROM 1 FOR 3), REPLACE(phone, '-', '')

Recorta espacios, extrae una subcadena, reemplaza un fragmento. Limpieza de cadenas del día a día.

Véase también:·
SPLIT_PARTPostgreSQL
Artículo
SPLIT_PART(email, '@', 2)   -- domain from an e-mail

Divide una cadena por un separador y toma la N-ésima parte. En MySQL — SUBSTRING_INDEX.

Véase también:···
ILIKEPostgreSQL
Artículo
WHERE name ILIKE '%ivan%'

LIKE sin distinción de mayúsculas (PostgreSQL). En MySQL, el LIKE normal ya ignora mayúsculas con la colación por defecto.

Véase también:···

Funciones de cadenas16

LEFT / RIGHT
Artículo
LEFT(code, 3), RIGHT(phone, 4)

Toma los primeros N caracteres (LEFT) o los últimos N (RIGHT) de una cadena.

Véase también:···
POSITION / STRPOSPostgreSQL
Artículo
POSITION('@' IN email), STRPOS(email, '@')

Posición de la primera aparición (desde 1), 0 si no se encuentra. STRPOS es la forma corta de PostgreSQL.

Véase también:···
LPAD / RPAD
Artículo
LPAD(id::text, 6, '0'), RPAD(name, 20, ' ')

Rellena una cadena hasta una longitud dada por la izquierda (LPAD) o la derecha (RPAD). Uso típico: rellenar un id con ceros.

Véase también:···
INITCAPPostgreSQL
Artículo
INITCAP('john DOE')   -- John Doe

Pone en mayúscula la primera letra de cada palabra y el resto en minúscula. No existe en MySQL.

Véase también:···
REPEAT
Artículo
REPEAT('ab', 3)   -- ababab

Repite una cadena N veces. Útil para marcadores de posición y gráficos de barras en texto.

Véase también:···
REVERSE
Artículo
REVERSE(name)

Invierte una cadena carácter a carácter. A veces se usa para indexar por sufijo.

Véase también:···
char_length
Artículo
char_length(name), char_length('açai')   -- 4

Longitud de la cadena en CARACTERES (no en bytes) — importa con UTF-8. Sinónimo de character_length.

Véase también:···
REGEXP_REPLACEPostgreSQL
Artículo
REGEXP_REPLACE(phone, '[^0-9]', '', 'g')

Reemplazo mediante expresión regular. La bandera 'g' reemplaza todas las coincidencias; sin ella, solo la primera.

Véase también:·
REGEXP_MATCHESPostgreSQL
Artículo
SELECT (REGEXP_MATCHES(url, '/(\d+)'))[1] AS id;

Devuelve los grupos capturados de la regex como un array. Con la bandera 'g' produce una fila por coincidencia.

Véase también:·
REGEXP_SPLIT_TO_ARRAYPostgreSQL
Artículo
REGEXP_SPLIT_TO_ARRAY('a, b,c', '\s*,\s*')

Divide una cadena por un separador regex en un array. También existe …TO_TABLE para filas.

Véase también:·
TRANSLATEPostgreSQL
Artículo
TRANSLATE(code, 'abc', 'xyz')   -- a->x, b->y, c->z

Sustitución carácter a carácter entre dos conjuntos. Los caracteres sobrantes del primer conjunto se eliminan. No es REPLACE.

Véase también:·
BTRIM / LTRIM / RTRIMPostgreSQL
Artículo
BTRIM(code, '0'), LTRIM(s), RTRIM(s, '/')

Recorta los caracteres indicados por ambos extremos (BTRIM), la izquierda (LTRIM) o la derecha (RTRIM); espacios por defecto.

Véase también:·
FORMATPostgreSQL
Artículo
FORMAT('Hi %s, id=%L', name, id)

Construye una cadena a partir de una plantilla: %s valor, %I identificador, %L literal seguro. Clave en SQL dinámico.

Véase también:····
STARTS_WITHPostgreSQL
Artículo
WHERE STARTS_WITH(path, '/api/')

Comprueba si una cadena empieza por un prefijo — más legible que LIKE 'x%'. Disponible desde PostgreSQL 11.

Véase también:···
ascii / chrPostgreSQL
Artículo
ascii('A')   -- 65
chr(65)      -- A

Código del primer carácter (ascii) y el carácter de un código (chr). En MySQL la inversa se llama CHAR.

Véase también:··
to_hexPostgreSQL
Artículo
to_hex(255)   -- 'ff'

Convierte un entero en su cadena hexadecimal. Útil para colores, máscaras de bits y depuración.

Véase también:··

Números y matemáticas16

ROUND(3.14159)        -- 3
ROUND(2.5)            -- banker? no: 3

Redondea al entero más cercano. Las mitades se redondean alejándose del cero (2.5 → 3).

Véase también:···
ROUND(x, n)
Artículo
ROUND(3.14159, 2)     -- 3.14
ROUND(12345.6, -2)    -- 12300

Redondea a n decimales; un n negativo redondea a la izquierda del punto. Solo funciona con numeric, no con float.

Véase también:···
CEIL / CEILING
Artículo
CEIL(4.1)   -- 5
CEIL(-4.1)  -- -4

Redondea hacia arriba al siguiente entero. CEILING es un sinónimo.

Véase también:···
FLOOR(4.9)   -- 4
FLOOR(-4.1)  -- -5

Redondea hacia abajo al entero anterior. Con negativos se aleja del cero.

Véase también:···
TRUNCPostgreSQL
Artículo
TRUNC(3.99)     -- 3
TRUNC(3.456, 2) -- 3.45

Descarta la parte decimal (hacia el cero), sin redondear. En MySQL es TRUNCATE(x, n).

Véase también:···
ABS(-7)   -- 7

Valor absoluto — la magnitud sin signo.

Véase también:···
MOD(10, 3)   -- 1

Resto de la división. Útil para «cada N-ésima fila» y la paridad; el signo del resultado sigue al dividendo.

Véase también:···
POWER(2, 10)   -- 1024

Eleva a una potencia. POW es un sinónimo.

Véase también:··
SQRT(144)   -- 12

Raíz cuadrada. Un argumento negativo provoca un error.

Véase también:··
EXP / LN
Artículo
EXP(1)    -- 2.7182818...
LN(2.718) -- ~1

Exponencial e^x y logaritmo natural (base e). LN(0) y LN(negativo) dan error.

Véase también:··
LOGPostgreSQL
Artículo
LOG(100)     -- 2  (base 10)
LOG(2, 8)    -- 3  (base 2)

En PostgreSQL LOG(x) es base 10, LOG(b, x) usa una base arbitraria. Atención: en MySQL LOG(x) es el logaritmo natural.

Véase también:··
SIGN(-42)  -- -1
SIGN(0)    -- 0

Signo de un número: -1, 0 o 1. Útil para bifurcar según la dirección del cambio.

Véase también:···
GREATEST / LEAST
Artículo
GREATEST(a, b, c), LEAST(a, b, c)

El mayor / menor entre los argumentos dentro de una fila (no es agregación). Los argumentos NULL se ignoran.

Véase también:···
RANDOMPostgreSQL
Artículo
SELECT * FROM t ORDER BY RANDOM() LIMIT 5;

Número aleatorio en [0,1). En MySQL es RAND(). ORDER BY RANDOM() da una muestra aleatoria, pero es costoso en tablas grandes.

Véase también:
DIV (integer division)PostgreSQL
Artículo
DIV(7, 2)   -- 3
7 / 2       -- 3 when both are int

División entera que descarta el resto. En PostgreSQL / ya divide entero si ambos operandos son enteros; MySQL usa el operador DIV para esto.

Véase también:···
WIDTH_BUCKETPostgreSQL
Artículo
WIDTH_BUCKET(score, 0, 100, 10)  -- bucket 1..10

Asigna un valor a un cubo de histograma de ancho igual entre dos límites. Para distribuciones y agrupación por rangos.

Véase también:····

Funciones de fecha y hora16

AGEPostgreSQL
Artículo
AGE(end_ts, start_ts)   -- or AGE(birthday) vs now
AGE('2024-03-01', '2024-01-15')

Diferencia entre dos fechas como intervalo (años/meses/días), no en segundos. Con un solo argumento cuenta desde hoy — útil para la edad.

DATE_PARTPostgreSQL
Artículo
DATE_PART('hour', created_at), DATE_PART('dow', created_at)

Forma de función de EXTRACT — extrae una parte de fecha/hora como número. El campo es una cadena, así que es fácil pasarlo dinámicamente.

Véase también:···
EXTRACT(EPOCH FROM …)
Artículo
EXTRACT(EPOCH FROM (ended_at - started_at)) AS seconds

Convierte un intervalo o timestamp en segundos (tiempo Unix). La forma habitual de medir una duración en segundos — luego divide entre 60/3600.

Véase también:···
TO_CHARPostgreSQL
Artículo
TO_CHAR(created_at, 'YYYY-MM-DD HH24:MI'), TO_CHAR(amount, 'FM999G999D00')

Formatea una fecha/número en una cadena mediante una plantilla (YYYY, MM, DD, HH24...). Las plantillas de PostgreSQL difieren del DATE_FORMAT de MySQL.

Véase también:·
TO_DATEPostgreSQL
Artículo
TO_DATE('2024-03-15', 'YYYY-MM-DD')

Convierte una cadena en una fecha con una plantilla explícita. Más fiable que el cast ::date cuando el formato no es estándar.

Véase también:·
TO_TIMESTAMPPostgreSQL
Artículo
TO_TIMESTAMP('2024-03-15 14:30', 'YYYY-MM-DD HH24:MI')
TO_TIMESTAMP(1710512400)   -- from Unix epoch

Convierte una cadena en un timestamp por plantilla, o construye un timestamptz a partir de segundos Unix (argumento numérico).

Véase también:·
CURRENT_TIMESTAMP / LOCALTIMESTAMP
Artículo
SELECT CURRENT_TIMESTAMP, LOCALTIMESTAMP;

Hora de inicio de la transacción: CURRENT_TIMESTAMP incluye zona horaria (timestamptz), LOCALTIMESTAMP no. Constante dentro de una misma transacción.

Véase también:·
CURRENT_TIME / CURRENT_DATE
Artículo
SELECT CURRENT_DATE, CURRENT_TIME;

Solo la fecha de hoy (CURRENT_DATE) o solo la hora (CURRENT_TIME) — sin paréntesis; son valores especiales de SQL, no funciones.

Véase también:·
Date arithmetic (date + int)PostgreSQL
Artículo
SELECT order_date + 7, due_date - 1, end_dt - start_dt AS days;

Puedes sumar/restar días enteros a un date (date + 7). Restar dos date da un número entero de días; restar dos timestamp da un intervalo.

Véase también:·
make_date / make_timePostgreSQL
Artículo
make_date(2024, 3, 15), make_time(14, 30, 0)

Construye una fecha u hora a partir de números separados de año/mes/día, hora/minuto/segundo — sin lidiar con cadenas de formato.

Véase también:·
make_timestamp / make_intervalPostgreSQL
Artículo
make_timestamp(2024, 3, 15, 14, 30, 0)
make_interval(days => 10, hours => 2)

Construye un timestamp o intervalo a partir de componentes numéricos. make_interval acepta argumentos con nombre (days =>, hours =>).

Véase también:·
AT TIME ZONEPostgreSQL
Artículo
ts_utc AT TIME ZONE 'Europe/Moscow'
local_ts AT TIME ZONE 'UTC'

Lleva un instante a otra zona horaria. Sobre un timestamptz da la hora local de esa zona; sobre un timestamp sin zona lo interpreta como hora de esa zona.

Véase también:··
JUSTIFY_INTERVAL / JUSTIFY_HOURSPostgreSQL
Artículo
JUSTIFY_HOURS(INTERVAL '36 hours')   -- 1 day 12:00:00

Normaliza un intervalo: convierte las horas sobrantes en días y los días en meses. Convierte «50 hours» en un legible «2 days 02:00:00».

Véase también:··
DATE_BINPostgreSQL
Artículo
DATE_BIN('15 minutes', ts, TIMESTAMP '2024-01-01')

Ajusta un timestamp al inicio de un bucket de ancho arbitrario (p. ej. 15 minutos) desde un origen. Más flexible que DATE_TRUNC. Postgres 14+.

Véase también:···
OVERLAPS
Artículo
(start_a, end_a) OVERLAPS (start_b, end_b)

Comprueba si dos periodos de tiempo se solapan. Útil para detectar conflictos de reservas o turnos.

Véase también:··
Time zone cast (timestamptz)PostgreSQL
Artículo
now()::timestamptz, '2024-03-15 10:00'::timestamp

timestamptz guarda el instante en UTC y aplica la zona al mostrarlo; timestamp es hora «ingenua» sin zona. Para eventos casi siempre quieres timestamptz.

Véase también:··

CASE y NULL4

CASE WHEN
Artículo
CASE
  WHEN score >= 90 THEN 'A'
  WHEN score >= 70 THEN 'B'
  ELSE 'C'
END

Lógica condicional en línea — como un if/else dentro de SELECT.

Véase también:··
COALESCE
Artículo
COALESCE(nickname, full_name, 'Anonymous')

Devuelve el primer valor no NULL de la lista.

Véase también:··
NULLIF
Artículo
NULLIF(divisor, 0)

Convierte un valor en NULL cuando es igual al segundo argumento. Útil para evitar la división por cero.

Véase también:··
NULL & IS DISTINCT FROM
Artículo
-- = NULL is never true — use IS NULL
WHERE deleted_at IS NULL
-- NULL-safe equality:
WHERE a IS DISTINCT FROM b

Comparar con NULL usando = siempre da «desconocido» (no TRUE/FALSE). Usa IS NULL para comprobar; usa IS DISTINCT FROM para igualdad segura ante NULL.

Véase también:··

JSON / JSONB19

JSONB ->>PostgreSQL
Artículo
payload->>'target'

Extrae un valor de un JSONB como text — para operaciones con cadenas y comparaciones.

Véase también:··
JSONB @>PostgreSQL
Artículo
payload @> '{"plan":"pro"}'

¿Contiene el JSONB el fragmento indicado? Usa un índice GIN — rápido en tablas grandes.

Véase también:···
GIN + jsonb_path_opsPostgreSQL
Artículo
CREATE INDEX idx ON events USING GIN (payload jsonb_path_ops)

Índice óptimo para consultas @> sobre JSONB. Más compacto que el jsonb_ops por defecto.

Véase también:
JSONB -> / ->>PostgreSQL
Artículo
data->'user'->>'name'   -- -> keeps json, ->> as text

-> extrae un campo/elemento como jsonb (para seguir navegando), ->> como text. Clave por cadena, índice de array por número.

Véase también:··
#> / #>>PostgreSQL
Artículo
data #>> '{address,city}'   -- text at a nested path

Lee un valor en una ruta anidada dada como array de claves: #> como jsonb, #>> como text. Más corto que encadenar ->.

Véase también:··
JSONB_BUILD_OBJECTPostgreSQL
Artículo
jsonb_build_object('id', id, 'name', name)

Construye un objeto JSON a partir de pares clave, valor alternados. Se conservan los tipos de los valores (los números siguen siendo números).

Véase también:····
JSONB_BUILD_ARRAYPostgreSQL
Artículo
jsonb_build_array(id, name, created_at)

Construye un array JSON a partir de los argumentos dados de cualquier tipo.

Véase también:····
JSONB_AGGPostgreSQL
Artículo
jsonb_agg(item ORDER BY created_at)

Agregado: reúne un grupo de filas en un array JSON. El ORDER BY interno fija el orden de los elementos.

Véase también:····
JSONB_ARRAY_ELEMENTSPostgreSQL
Artículo
SELECT e FROM t, jsonb_array_elements(t.tags) AS e

Expande un array JSON en filas — una fila por elemento. La variante _text devuelve text en lugar de jsonb.

Véase también:·····
JSONB_ARRAY_LENGTHPostgreSQL
Artículo
jsonb_array_length(data->'items')

Longitud de un array JSON. Da error si el valor no es un array — protégelo con jsonb_typeof.

Véase también:·····
JSONB_SETPostgreSQL
Artículo
jsonb_set(data, '{address,city}', '"Lima"')

Devuelve una copia del JSON con el valor de la ruta reemplazado. create_missing=true (por defecto) añade la clave si falta.

Véase también:·
JSONB_EACHPostgreSQL
Artículo
SELECT key, value FROM jsonb_each(data)

Expande un objeto JSON en filas (key, value) — una por clave. La variante _text devuelve value como text.

Véase también:·····
JSONB_OBJECT_KEYSPostgreSQL
Artículo
SELECT jsonb_object_keys(data)

Devuelve los nombres de las claves de nivel superior de un objeto JSON, una fila por clave.

Véase también:·····
? / ?| / ?&PostgreSQL
Artículo
data ? 'email'        -- has key?
data ?| array['a','b'] -- any of these keys?

Pruebas de existencia de claves: ? una clave, ?| alguna de estas, ?& todas. Solo nivel superior; admiten índice GIN.

Véase también:·····
JSONB || (merge)PostgreSQL
Artículo
data || '{"verified":true}'

Fusiona dos valores JSONB: las claves de la derecha sobrescriben las de la izquierda (superficial, no recursivo). Útil para una actualización parcial.

Véase también:·
JSONB - / #- (delete)PostgreSQL
Artículo
data - 'temp'              -- drop a key
data #- '{address,zip}'    -- drop at a path

Elimina una clave/elemento: - por clave o índice de nivel superior, #- en una ruta anidada. Devuelve un nuevo JSONB.

Véase también:·
to_jsonbPostgreSQL
Artículo
to_jsonb(row_var)   -- whole row as a json object

Convierte cualquier valor/fila/array de SQL en jsonb. Una fila entera de la tabla se vuelve un objeto JSON columna → valor.

Véase también:·····
JSONB_TYPEOFPostgreSQL
Artículo
jsonb_typeof(data->'price')   -- 'number','string',...

El tipo del valor JSON como text: object, array, string, number, boolean, null. Útil antes de jsonb_array_length, etc.

Véase también:·····
JSONB_PRETTYPostgreSQL
Artículo
jsonb_pretty(data)

Formatea JSONB con sangría para una salida legible o depuración.

Véase también:·····

Rendimiento e índices7

Partial indexPostgreSQL
Artículo
CREATE INDEX i ON orders (id) WHERE status = 'pending';

Índice solo sobre el subconjunto «caliente» de filas — más compacto y más rápido de recorrer.

Véase también:····
Composite index
Artículo
CREATE INDEX i ON orders (customer_id, created_at DESC);

Cubre el filtro y la ordenación en una sola lectura. El orden de las columnas importa.

Véase también:····
Sargable WHERE
Artículo
-- bad : WHERE EXTRACT(YEAR FROM ts) = 2024
-- good: WHERE ts >= '2024-01-01' AND ts < '2025-01-01'

No envuelvas la columna en una función — el índice no se usará. Reescríbelo como un rango.

Véase también:····
NOT EXISTS vs NOT IN
Artículo
-- NOT IN collapses to 0 rows on any NULL
WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);

NOT IN se rompe sin avisar ante cualquier NULL en la subconsulta. NOT EXISTS es seguro frente a NULL.

Véase también:···
CONCURRENTLYPostgreSQL
Artículo
CREATE INDEX CONCURRENTLY i ON events (user_id, kind);

Construye un índice en una tabla caliente sin un bloqueo pesado. Está prohibido dentro de una transacción.

Véase también:····
EXPLAIN
Artículo
EXPLAIN SELECT * FROM orders WHERE user_id = 5;

Muestra el plan de la consulta sin ejecutarla: qué exploraciones (Seq Scan / Index Scan), orden de joins, filas estimadas.

Véase también:····
EXPLAIN (ANALYZE, BUFFERS)
Artículo
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM orders WHERE user_id = 5;

Ejecuta la consulta y muestra el tiempo y las filas REALES frente a la estimación. Una gran diferencia estimación↔real indica estadísticas obsoletas o un índice ausente.

Véase también:····

Transacciones4

SELECT … FOR UPDATE
Artículo
BEGIN;
SELECT * FROM accounts WHERE id IN (1, 2) FOR UPDATE;
UPDATE accounts SET balance = balance - 200 WHERE id = 1;
UPDATE accounts SET balance = balance + 200 WHERE id = 2;
COMMIT;

Bloquea filas hasta el final de la transacción. Estándar para las transferencias de dinero.

Véase también:··
Conditional UPDATE
Artículo
UPDATE accounts SET balance = balance - 200
WHERE id = 1 AND balance >= 200;

Comprobación y actualización en una única sentencia atómica. Si se actualizan 0 filas — muestra «fondos insuficientes».

Véase también:··
FOR UPDATE SKIP LOCKED
Artículo
SELECT id FROM jobs
WHERE status = 'pending'
ORDER BY id
FOR UPDATE SKIP LOCKED LIMIT 1;

Cola de workers: cada worker toma su propia tarea, saltándose las filas bloqueadas por otros.

Véase también:··
Atomic counter
Artículo
UPDATE counters SET n = n + 1 WHERE id = 1;

Un único UPDATE incrementa el contador de forma segura ante la concurrencia. SELECT seguido de UPDATE pierde incrementos.

Véase también:··

Control de acceso (GRANT/REVOKE)4

GRANT SELECT, INSERT ON orders TO analyst;

Concede privilegios sobre un objeto a un rol/usuario. Enumera las acciones necesarias (SELECT, INSERT, UPDATE, DELETE).

Véase también:··
REVOKE
Artículo
REVOKE INSERT ON orders FROM analyst;

Retira privilegios concedidos anteriormente.

Véase también:··
CREATE ROLE
Artículo
CREATE ROLE analyst LOGIN PASSWORD 'secret';

Crea un rol (usuario/grupo). Los privilegios se conceden al rol y los usuarios son miembros de él.

Véase también:··
Read-only role
Artículo
GRANT USAGE ON SCHEMA public TO readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
  GRANT SELECT ON TABLES TO readonly;

El patrón estándar de solo lectura: acceso al esquema + SELECT en todas las tablas + una regla para futuras tablas con ALTER DEFAULT PRIVILEGES.

Véase también:··