Aprender  /  Guías

SQL ASOF JOIN explicado: asociar cada fila con el valor más reciente, en cada motor

¿Cuál era el precio cuando se hizo la operación? ¿Qué tipo de cambio se aplicaba en la fecha de la factura? ¿Qué sabía el modelo en el momento de la predicción? Son preguntas "ASOF", y en 2026 casi todos los motores tienen un join para ellas. Así funciona, con ejemplos que ejecutamos.

Guía9 min de lecturaActualizado el 9 de noviembre de 2026
SQLPythonAnálisis de datos
Todas las guías y chuletas

Un join normal une filas cuando las claves son iguales. Muchas preguntas reales necesitan otra cosa: la fila con la marca de tiempo más reciente igual o anterior a otra. El precio de una acción en el momento de una compra. El tipo de cambio vigente el día de una factura. El plan del cliente cuando abrió una incidencia. Eso es un ASOF JOIN ("as of", es decir, "a fecha de"). Snowflake, DuckDB, ClickHouse y Polars lo tienen, y Apache Spark lo añadió en la versión 4.3. Esta guía explica la idea una vez y luego muestra la sintaxis en cada herramienta.

La idea, con un ejemplo

Usaremos siempre las mismas dos tablas pequeñas. Cada operación debe recibir la última cotización del mismo valor igual o anterior a la hora de la operación.

trade_idsymhora de la operaciónÚltima cotización igual o anteriorprecio
1A10:00:0510:00:0010.0
2A10:00:2010:00:1010.5
3B10:00:01ninguna aún (la primera cotización de B es a las 10:00:15)NULL
4B10:00:3010:00:1520.0

Fíjate en la operación 2: también hay una cotización a las 10:00:25, pero llegó después de la operación, así que no debe usarse. Y la operación 3 no tiene ninguna cotización anterior. Qué le pasa depende del tipo de join, la fuente de errores más habitual.

Cómo piensa un ASOF JOIN
Claves igualesmismo valor, cliente o cuenta
Desigualdadhora de la derecha igual o anterior a la de la izquierda
Solo unaúnicamente la coincidencia más cercana
Mantener o descartarLEFT mantiene las filas sin coincidencia

La sintaxis en cada motor

Todos los ejemplos de abajo devuelven los precios 10.0, 10.5, NULL y 20.0. Las versiones de DuckDB 2.0, Spark 4.3, Polars 2.1 y pandas 3.1 las ejecutamos nosotros.

SQL
SELECT t.trade_id, t.sym, t.ts, q.price
FROM trades t
ASOF JOIN quotes q
  MATCH_CONDITION (t.ts >= q.ts)
  ON t.sym = q.sym;

MATCH_CONDITION contiene la única desigualdad (>=, >, <= o <); ON contiene las claves iguales. Las filas sin coincidencia vuelven con NULL, como en un left join.

¿Sin ASOF JOIN? Usa esta alternativa

BigQuery y PostgreSQL no tienen la palabra clave ASOF, pero dos patrones dan la misma respuesta. En nuestras pruebas, los dos devolvieron resultados idénticos a las versiones ASOF.

QUALIFY

BigQuery y la mayoría
Idea
unir todas las cotizaciones anteriores y quedarse con la última por operación
  • Corto y legible
  • Construye antes todas las coincidencias anteriores, así que puede ser lento con tablas grandes

Válido para miles o millones de filas.

LATERAL

El mejor en PostgreSQL
Idea
para cada operación, buscar una fila con ORDER BY y LIMIT 1
  • En PostgreSQL usa un índice sobre (sym, ts), así que escala bien
  • No disponible en BigQuery

La mejor opción en PostgreSQL.

SQL
-- QUALIFY version (WHERE TRUE is harmless and keeps BigQuery happy,
-- which has long asked for WHERE, GROUP BY or HAVING next to QUALIFY)
SELECT t.trade_id, q.price
FROM trades t
LEFT JOIN quotes q
  ON q.sym = t.sym AND q.ts <= t.ts
WHERE TRUE
QUALIFY ROW_NUMBER() OVER (PARTITION BY t.trade_id ORDER BY q.ts DESC) = 1;

-- LATERAL version (PostgreSQL)
SELECT t.trade_id, q.price
FROM trades t
LEFT JOIN LATERAL (
  SELECT price FROM quotes q
  WHERE q.sym = t.sym AND q.ts <= t.ts
  ORDER BY q.ts DESC
  LIMIT 1
) q ON TRUE;

Cuatro errores que evitar

  1. 1

    Perder filas sin querer

    Comprueba si el ASOF JOIN simple de tu motor es inner. En DuckDB, ClickHouse y Spark escribe LEFT si todas las filas de la izquierda deben quedarse.

  2. 2

    Equivocarse de dirección

    ">=" significa el último valor igual o anterior; "<=" el siguiente valor igual o posterior. pandas los llama backward y forward; Polars habla de estrategias.

  3. 3

    Asociar valores demasiado viejos

    Una cotización de ayer sigue siendo "la última". Añade una tolerancia en pandas o Polars, o un filtro como t.ts - q.ts <= INTERVAL 1 HOUR en SQL.

  4. 4

    Olvidar las claves iguales

    Sin ON t.sym = q.sym, una operación en A puede recoger una cotización de B.

Correcto en el tiempo
Usar solo los datos que existían en el momento analizado.
Coincidencia hacia atrás
La última fila de la derecha igual o anterior a la fila de la izquierda; lo predeterminado en la mayoría de herramientas.
Coincidencia hacia delante
La primera fila de la derecha igual o posterior a la fila de la izquierda, por ejemplo la siguiente entrega tras un pedido.
Tolerancia
La distancia máxima permitida entre los dos tiempos; las coincidencias más antiguas devuelven NULL.

Pon a prueba lo que has aprendido

1/3¿Qué devuelve un ASOF JOIN para cada fila de la izquierda?

2/3En DuckDB, ¿qué pasa con las operaciones sin cotización anterior si escribes ASOF JOIN sin LEFT?

3/3BigQuery no tiene ASOF JOIN. ¿Qué alternativa funciona?

Más SQL: los joins de SQL explicados, las funciones de ventana explicadas y la chuleta de SQL. Sobre las herramientas: novedades de Polars 2.1 y DuckDB 2.0.

Fuentes: documentación de Snowflake sobre ASOF JOIN; documentación de DuckDB, ClickHouse, pandas (merge_asof) y Polars (join_asof); notas de versión de Apache Spark 4.3.0 (30 de octubre de 2026). Ejemplos probados con DuckDB 2.0.0, PySpark 4.3.0, Polars 2.1.0 y pandas 3.1.0; la sintaxis de Snowflake, ClickHouse, BigQuery y PostgreSQL sigue su documentación.

Alessandro Ecclesie AgazziEscrito por Alessandro Ecclesie Agazzi, analytics engineer en Londres. Actualizado el 9 de noviembre de 2026. Sobre mí

¿Te ha resultado útil?

Aquí se publican con regularidad nuevas guías y artículos sobre las novedades en datos e IA. Sígueme en LinkedIn o comparte este artículo con un compañero.