- Categories:
ASOF JOIN¶
An ASOF JOIN operation combines rows from two tables based on timestamp values that follow each other, precede each other, or match exactly. For each row in the first (or left) table, the join finds a single row in the second (or right) table that has the closest timestamp value. The qualifying row on the right side is the closest match, which could be equal in time, earlier in time, or later in time, depending on the specified comparison operator.
This topic describes how to use the ASOF JOIN construct in the FROM clause. For a more detailed conceptual explanation of ASOF joins, see Analyzing time-series data.
See also JOIN, which covers the syntax for other standard join types, such as inner and outer joins.
Syntax¶
The following FROM clause syntax is specific to ASOF JOIN:
Parameters¶
FROMThe first (or left) table in the FROM clause is assumed to contain records that either follow (in time), precede, or are exactly synchronized with, the records in the second (or right) table. When there is no match for a row in the left table, the columns from the right table are null-padded.
In addition to regular tables and views, any object reference can be used in an ASOF JOIN. See FROM.
ASOF JOIN can be used in most contexts where joins are supported. For information about some restrictions, see Usage Notes.
MATCH_CONDITION ( left_table.timecol comparison_operator right_table.timecol )This condition names the specific timestamp columns to be compared in each table.
The order of tables is important in the condition. The left table must be named first.
The parentheses are required.
The comparison operator must be one of the following:
>=,<=,>,<. The equals operator (=) is not supported.All of the following data types are supported: DATE, TIME, DATETIME, TIMESTAMP, TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZ.
You can also use NUMBER columns in the match condition. For example, you might have NUMBER columns that contain UNIX timestamps (which define the number of seconds that have elapsed since January 1st, 1970).
The data types of the two matched columns don’t have to be exactly the same, but they must be compatible.
ON table.col = table.col [ AND ... ] | USING (column_list)The optional ON or USING clause defines one or more equality conditions on columns in the two tables, for the purpose of logically grouping the results of the query.
For general information about ON and USING, see JOIN. Note that a join specified with USING projects one of the joining columns in its intermediate result set, not both. A join specified with an ON clause projects both joining columns.
The following notes are specific to ASOF JOIN:
The comparison operator in the ON clause must be the equal sign (=).
The ON clause cannot contain disjuncts (conditions connected with OR). Conditions connected with AND are supported.
Each side of a condition must refer to only one of the two tables in the join. However, the order of the table references doesn’t matter.
Each condition can be enclosed in parentheses, but they aren’t required.
See also More Details on Join Behavior and Specifying a USING condition instead of an ON condition.
Usage notes¶
If no match is found in the right table for a given row, the result is null-padded for the selected columns from the right table. (ASOF joins are similar to left outer joins in this respect.)
If you use TIME columns in the match condition (as opposed to one of the timestamp types), you might need to set the TIME_OUTPUT_FORMAT parameter in order to see the exact TIME values that are being compared when you look at ASOF JOIN query results. By default, the display of a TIME column truncates milliseconds. See TIME columns in the match condition.
You can use more than one ASOF join in the same query as long as all of the syntax rules are followed for each join. Each join must be immediately followed by its own MATCH_CONDITION. You cannot apply a single MATCH_CONDITION to multiple ASOF joins. See Multiple ASOF joins in a query.
ASOF joins are not supported for joins with LATERAL table functions or LATERAL inline views. For more information about lateral joins, see LATERAL.
An ASOF join with a self-reference is not allowed in a RECURSIVE common table expression (CTE). For information about CTEs, see WITH.
The EXPLAIN output for ASOF JOIN queries identifies the ON (or USING) conditions and the MATCH_CONDITION. For example, in text or tabular format, output similar to the following text appears above the table scans in the plan:
Query profiles also clearly identify the ASOF JOIN operation in the plan. In this example, you can see that the table scan reads 22M rows from the left table, which are all preserved by the join. The profile also shows the match condition for the join.
You can specify the ASOF keyword in a semantic view to perform the ASOF JOIN operation on two logical tables in the view. For information, see Using a date, time, timestamp, or numeric range to join logical tables.
More details on join behavior¶
The optional ON (or USING) conditions for ASOF JOIN provide a way of grouping or partitioning table rows before the final matching rows are singled out by the required match condition. If you want the rows from the joined tables to be grouped on one or more dimensions that the tables share (stock symbol, location, city, state, company name, etc.), use an ON condition. If you don’t use an ON condition, each row from the left table may be matched (by time) with any row from the right table in the final result set.
In the following example, tables left_table and right_table have values A, B, etc.
in column c1, and values 1, 2, etc. in column c2. Column c3 is a TIME column, and c4 is a numeric value (column of interest).
First, create and load the two tables:
If c1 and c2 are both ON condition columns in the query, a row in the left table only matches a row in the right table
when A and 1, A and 2, B and 1, or B and 2 are found in both tables.
If no match is found for such values, the right table columns are null-padded.
If the ON conditions are removed, any combination of values in c1 and c2 may be matched in the final result.
Only the match condition determines the results.
Expected behavior when “ties” exist in the right table¶
ASOF JOIN queries always attempt to match a single row in the left table with a single row in the right table. This behavior is true even if two (or more) rows in the right table are identical and qualify for the join. When such ties exist and you run the same join query multiple times, you might get different results. The results are non-deterministic because any one of the tying rows might be returned. If you’re unsure about the results of ASOF JOIN queries, check for exact matches in the timestamp values for rows in the right table.
For example, using the same tables from the examples in the previous section, add a right_id column to right_table
and insert the following rows:
Two of the rows are identical except for their right_id values. Now run the following ASOF JOIN query:
Note that rows A1 and A2 from right_table both qualify for the join, but only A2 is returned. On a
subsequent run of the same query, A1 could be returned instead.
Rewriting ASOF JOIN queries to reduce scans on the right table¶
When the cardinality of the ON or USING join column in the left table is lower than the cardinality of the join column in the right table, the optimizer does not prune the unmatched rows from the right table. Therefore, more rows than are needed for the join will be scanned from the right table. This behavior typically occurs when the query includes a highly selective filter on a non-join column from the left table, and the filter reduces the cardinality of the join column.
You can work around this problem by manually reducing the rows that qualify for the join. For example, the
original query has the following pattern, and t1.c1 has lower cardinality than t2.c1:
You can rewrite the query as follows to manually select the rows from t2 where t2.c1 values are
found in t1.c1:
Using ASOF and MATCH_CONDITION as object names and aliases¶
Use of the ASOF and MATCH_CONDITION keywords in SELECT command syntax is restricted:
If a SELECT statement uses ASOF or MATCH_CONDITION as the name of a table, view, or inline view, you must identify it as follows:
If the object was created with double quotes in the name, use the same double-quoted name.
If the object was created without double quotes in the name, use double quotes and capital letters.
For example, the following statements are no longer allowed and return errors:
If you created the objects with double quotes, fix the problem by using double quotes:
If you created the objects without double quotes, fix the problem by using double quotes and capital letters:
See also Unquoted identifiers.
If a SELECT statement uses ASOF or MATCH_CONDITION as an alias, you must use AS before the alias or double-quote the alias. For example, the following statements are no longer allowed and return errors:
Fix the problem in one of the following ways:
Examples¶
The following examples demonstrate the expected behavior of ASOF JOIN queries. Start by running the query under Joining two tables on the closest match (alignment), then proceed with the examples here.
NULL-padded results¶
Insert a new row into the trades table with a date that’s a day earlier than the existing rows in both
trades and quotes:
Now run the first example query again. Note that the query returns four rows, but the new row is null-padded.
There is no row in the quotes table that qualifies for the match condition.
The columns from trades are returned, and the corresponding columns from quotes are null-padded.
Using a different comparison operator in the match condition¶
Following on from the previous example, the results of the query change again when the comparison operator in the
match condition is changed. The following query specifies the <= operator (instead of >=):
Specifying a USING condition instead of an ON condition¶
You can use an ON condition or a USING condition with ASOF JOIN queries. The following query is equivalent to the
previous query, but it replaces ON with USING. The syntax USING(stock_symbol) implies the condition
t.stock_symbol=q.stock_symbol.
Inner join to a third table¶
The following example adds a third companies table to the join in order to pick the company name for each stock symbol.
You can use a regular INNER JOIN with an ON condition (or some other standard join syntax) to add the third table.
However, note that USING(stock_symbol) would not work here because the reference to stock_symbol would be ambiguous.
Numbers as timestamps¶
The following example demonstrates that the match condition can compare numeric values.
In this case, the tables have UNIX timestamp values stored in NUMBER(38,0) columns. 1696150805
is equivalent to 2023-10-30 10:20:05.000 (three seconds later than 1696150802).
TIME columns in the match condition¶
The following examples join tables that contain weather observations. The observations in these tables are recorded in TIME columns. You can create and load the tables as follows:
When you run the first query, some of the TIME values appear to be exactly the same in the result set (14:42:59, 14:42:44).
To return a more precise display of TIME values, including milliseconds, run the following ALTER SESSION command, then run the ASOF JOIN query again:
Multiple ASOF joins in a query¶
The following example shows how to connect a sequence of two or more ASOF joins in a single query block.
The three tables (snowtime, raintime, preciptime) all contain weather observations that were recorded in
specific locations at specific times. The column of interest is the observation column. The rows are logically grouped by state.
Less than and greater than comparison operators¶
Following on from the previous example, two ASOF joins are specified, but this time the first match condition uses the >
operator and the second uses the < operator. The result is a single row that returns data from all three tables, and three rows
that return data from two of the tables. Many of the columns in the result set are null-padded.
Logically, the query finds only one row where the observed time from the snowtime table was later than the observed time from the
raintime table but earlier than the observed time from the preciptime table.
Examples of expected error cases¶
The following examples show queries that return expected syntax errors.
Having declared that snowtime s is the left table, you cannot begin the match condition with a reference to the right table, preciptime p:
Only the >=, <=, >, and < operators are allowed in match conditions:
The ON clause for ASOF JOIN must contain equality conditions:
An ON clause equality condition cannot contain disjunctions:
ASOF joins cannot be used with LATERAL inline views: