Apprendre  /  Guides

SQL ASOF JOIN expliqué : associer chaque ligne à la valeur la plus récente, dans chaque moteur

Quel était le prix au moment de la transaction ? Quel taux de change s'appliquait à la date de la facture ? Que savait le modèle au moment de la prédiction ? Ce sont des questions « ASOF », et en 2026 presque chaque moteur a une jointure pour y répondre. Voici comment elle fonctionne, avec des exemples que nous avons exécutés.

Guide9 min de lectureMis à jour le 9 novembre 2026
SQLPythonAnalyse de données
Tous les guides et antisèches

Une jointure normale associe des lignes quand les clés sont égales. Beaucoup de vraies questions demandent autre chose : la ligne avec l'horodatage le plus récent égal ou antérieur à un autre horodatage. Le prix d'une action au moment d'un achat. Le taux de change en vigueur le jour d'une facture. L'offre du client quand il a ouvert un ticket. C'est un ASOF JOIN (« as of », c'est-à-dire « à la date de »). Snowflake, DuckDB, ClickHouse et Polars le proposent, et Apache Spark l'a ajouté dans la version 4.3. Ce guide explique l'idée une fois, puis montre la syntaxe dans chaque outil.

L'idée, avec un exemple

Nous utiliserons partout les deux mêmes petites tables. Chaque transaction doit recevoir la dernière cotation du même titre égale ou antérieure à l'heure de la transaction.

trade_idsymheure de transactionDernière cotation égale ou antérieureprix
1A10:00:0510:00:0010.0
2A10:00:2010:00:1010.5
3B10:00:01aucune encore (la première cotation de B est à 10:00:15)NULL
4B10:00:3010:00:1520.0

Regardez la transaction 2 : il existe aussi une cotation à 10:00:25, mais elle est arrivée après la transaction, donc elle ne doit pas servir. Et la transaction 3 n'a aucune cotation antérieure. Ce qui lui arrive dépend du type de jointure, la source d'erreurs la plus fréquente.

Comment raisonne un ASOF JOIN
Clés égalesmême titre, client ou compte
Inégalitéheure de droite égale ou antérieure à celle de gauche
Une seuleuniquement la correspondance la plus proche
Garder ou écarterLEFT garde les lignes sans correspondance

La syntaxe dans chaque moteur

Chaque exemple ci-dessous renvoie les prix 10.0, 10.5, NULL et 20.0. Nous avons exécuté nous-mêmes les versions DuckDB 2.0, Spark 4.3, Polars 2.1 et pandas 3.1.

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 contient l'unique inégalité (>=, >, <= ou <) ; ON contient les clés égales. Les lignes sans correspondance reviennent avec des NULL, comme dans une jointure gauche.

Pas d'ASOF JOIN ? Utilisez cette solution de repli

BigQuery et PostgreSQL n'ont pas de mot-clé ASOF, mais deux schémas donnent la même réponse. Dans nos tests, les deux ont renvoyé des résultats identiques aux versions ASOF.

QUALIFY

BigQuery et la plupart
Idée
joindre toutes les cotations antérieures, puis garder la dernière par transaction
  • Court et lisible
  • Construit d'abord toutes les correspondances antérieures, donc peut être lent sur de grosses tables

Convient de quelques milliers à quelques millions de lignes.

LATERAL

Le meilleur dans PostgreSQL
Idée
pour chaque transaction, chercher une ligne avec ORDER BY et LIMIT 1
  • Utilise un index sur (sym, ts) dans PostgreSQL, donc passe bien à l'échelle
  • Non pris en charge dans BigQuery

La meilleure option dans 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;

Quatre erreurs à éviter

  1. 1

    Perdre des lignes par accident

    Vérifiez si le simple ASOF JOIN de votre moteur est interne. Dans DuckDB, ClickHouse et Spark, écrivez LEFT si chaque ligne de gauche doit rester.

  2. 2

    Se tromper de sens

    ">=" signifie la dernière valeur égale ou antérieure ; "<=" la prochaine valeur égale ou postérieure. pandas les appelle backward et forward ; Polars parle de stratégies.

  3. 3

    Associer des valeurs trop anciennes

    Une cotation d'hier reste « la dernière ». Ajoutez une tolérance dans pandas ou Polars, ou un filtre comme t.ts - q.ts <= INTERVAL 1 HOUR en SQL.

  4. 4

    Oublier les clés égales

    Sans ON t.sym = q.sym, une transaction sur A peut récupérer une cotation de B.

Correct dans le temps
N'utiliser que les données qui existaient au moment analysé.
Correspondance en arrière
La dernière ligne de droite égale ou antérieure à la ligne de gauche ; le comportement par défaut de la plupart des outils.
Correspondance en avant
La première ligne de droite égale ou postérieure à la ligne de gauche, par exemple la prochaine livraison après une commande.
Tolérance
L'écart maximal autorisé entre les deux temps ; les correspondances plus anciennes renvoient NULL.

Testez vos connaissances

1/3Que renvoie un ASOF JOIN pour chaque ligne de gauche ?

2/3Dans DuckDB, que deviennent les transactions sans cotation antérieure si vous écrivez ASOF JOIN sans LEFT ?

3/3BigQuery n'a pas d'ASOF JOIN. Quelle alternative fonctionne ?

Plus de SQL : les jointures SQL expliquées, les fonctions de fenêtre expliquées et l'aide-mémoire SQL. Sur les outils : les nouveautés de Polars 2.1 et DuckDB 2.0.

Sources : documentation de Snowflake sur ASOF JOIN ; documentation de DuckDB, ClickHouse, pandas (merge_asof) et Polars (join_asof) ; notes de version d'Apache Spark 4.3.0 (30 octobre 2026). Exemples testés avec DuckDB 2.0.0, PySpark 4.3.0, Polars 2.1.0 et pandas 3.1.0 ; la syntaxe de Snowflake, ClickHouse, BigQuery et PostgreSQL suit leur documentation.

Alessandro Ecclesie AgazziÉcrit par Alessandro Ecclesie Agazzi, analytics engineer à Londres. Mis à jour le 9 novembre 2026. À propos

Cet article vous a été utile ?

De nouveaux guides et décryptages des nouveautés en data et en IA paraissent ici régulièrement. Suivez-moi sur LinkedIn ou partagez cet article avec un collègue.