CertSafari
    Snowflake SnowPro Advanced: Data Analyst (DAA-C01)· Lessons

    Domain 1 · Lesson 2/19

    Snowflake Joins, Set Operators, ASOF JOIN and QUALIFY for Data Discovery

    Perform data discovery to identify what is needed from the available datasets.

    10 min read
    2.43% of exam
    5 sources
    Published 5 Oct 2026
    Docs as of 4 Oct 2026

    What you will be able to do

    • Pick the join type whose row-preservation behaviour matches the requirement
    • Combine or compare query results with UNION, UNION ALL, INTERSECT and MINUS
    • Write an ASOF JOIN with a valid MATCH_CONDITION and predict where it null-pads
    • Place WHERE, HAVING and QUALIFY correctly in a query's evaluation order

    1.Joins: which rows survive

    Once discovery shows that a required element lives in another table, you need a join. The main choice is what happens to rows that have no match. Snowflake's recommended form is JOIN with an ON subclause. A bare JOIN, with no INNER or OUTER keyword, is an inner join.

    Standard join types and the rows each produces
    Join typeResult
    o1 INNER JOIN o2For each row of o1, one row for each matching row of o2
    o1 LEFT OUTER JOIN o2Inner-join rows plus each unmatched o1 row, with o2 columns null
    o1 RIGHT OUTER JOIN o2Inner-join rows plus each unmatched o2 row, with o1 columns null
    o1 FULL OUTER JOIN o2Joined rows plus unmatched rows from both sides, null-extended
    o1 CROSS JOIN o2Cartesian product; cannot take an ON clause
    o1 NATURAL JOIN o2Join on the common columns, which appear once in the output; cannot take an ON clause

    USING (key_column) is shorthand for an equality on a column that has the same name in both tables. With SELECT *, that column appears only once. The most expensive mistake is to leave out the join condition. An INNER JOIN with no ON, or a comma join with no WHERE, produces a Cartesian product. Almost all of that output pairs rows that are not related.

    Checkpoint 1 of 6· Check yourself

    A colleague writes SELECT * FROM orders JOIN customers; with no ON or USING clause. What does Snowflake return?

    Sources1

    2.Set operators: stacking and comparing result sets

    Joins add columns side by side. Set operators stack rows from separate queries. During discovery they answer questions such as "which keys appear in both sources?" or "which ones are missing from the target?" The plain forms match columns by position, so each query must select the same number of columns, with compatible types and the same meaning. The output column names come from the first query. If you write SELECT * on two tables whose columns are in a different order, you get wrong results without any error. UNION BY NAME and UNION ALL BY NAME match columns by name instead, and fill a column that is missing from one input with NULL.

    Set operators compared
    OperatorReturnsDuplicates
    UNION (same as UNION DISTINCT)Rows from both queries, matched by positionEliminated
    UNION ALLRows from both queries, matched by positionKept
    UNION [ALL] BY NAMERows from both queries, matched by column nameEliminated (BY NAME) or kept (ALL BY NAME)
    INTERSECTRows that appear in both result setsEliminated
    MINUS / EXCEPTRows from the first query that are not in the secondn/a
    INTERSECT finds postal codes that have both a sales office and a customersql
    SELECT postal_code FROM sales_office_postal_example
    INTERSECT
    SELECT postal_code FROM customer_postal_example
    ORDER BY postal_code;
    
    +-------------+
    | POSTAL_CODE |
    |-------------|
    | 94061       |
    | 98005       |
    +-------------+

    With MINUS, the order of the queries matters. Swapping them answers the opposite question. Precedence follows ANSI: INTERSECT binds tighter than UNION [ALL] and MINUS, which have equal precedence and are evaluated from left to right. Snowflake recommends adding parentheses whenever you mix operators.

    Checkpoint 2 of 6· Fill the gap

    Sales offices sit in 94061, 94070, 98116 and 98005; customers are in 94066, 94061, 98444 and 98005. Which operator produces this output?

    SELECT postal_code FROM sales_office_postal_example
     ? 
    SELECT postal_code FROM customer_postal_example
    ORDER BY postal_code;
    
    +-------------+
    | POSTAL_CODE |
    |-------------|
    | 94070       |
    | 98116       |
    +-------------+

    Checkpoint 3 of 6· Exam question

    During discovery, an analyst must list customer IDs that exist in the CRM system but have no matching record in billing. Which query returns exactly those IDs?

    Sources2

    3.ASOF JOIN: the closest match in time

    Time-series sources rarely line up exactly. A trade at 09:00:05 has no quote stamped at exactly 09:00:05, so an equality join finds nothing. ASOF JOIN solves this. For each left-hand row it returns one right-hand row: the closest one in time, in the direction set by the comparison operator. The required MATCH_CONDITION names the left table's time column first, and its parentheses are mandatory. The supported types are DATE, TIME and the timestamp types, as well as NUMBER (for example UNIX epoch seconds). An optional ON or USING clause, which allows only equality conditions joined with AND, partitions the match. Use it so that a stock is matched only with quotes for the same stock.

    ASOF JOIN with ON grouping: unmatched left rows are null-paddedsql
    SELECT *
      FROM left_table l ASOF JOIN right_table r
        MATCH_CONDITION(l.c3>=r.c3)
        ON(l.c1=r.c1 and l.c2=r.c2)
      ORDER BY l.c1, l.c2;
    
    +----+----+----------+------+------+------+----------+------+
    | C1 | C2 | C3       |   C4 | C1   | C2   | C3       |   C4 |
    |----+----+----------+------+------+------+----------+------|
    | A  |  1 | 09:15:00 | 3.21 | A    |  1   | 09:14:00 | 3.19 |
    | A  |  2 | 09:16:00 | 3.22 | NULL | NULL | NULL     | NULL |
    | B  |  1 | 09:17:00 | 3.23 | B    |  1   | 09:16:00 | 3.04 |
    | B  |  2 | 09:18:00 | 4.23 | NULL | NULL | NULL     | NULL |
    +----+----+----------+------+------+------+----------+------+

    Remove the ON clause and only time decides the match, so A-rows can pair with B-rows. Changing >= to <= reverses the direction and finds the next quote instead of the previous one. If two right-table rows tie on the timestamp, Snowflake still returns only one of them, and which one can differ between runs. A few further rules: you can use several ASOF joins in one query, but each needs its own MATCH_CONDITION. ASOF does not work with LATERAL table functions or LATERAL inline views. You can add a regular INNER JOIN, for example to look up company names, after the ASOF join.

    Checkpoint 4 of 6· Check yourself

    Which MATCH_CONDITION is invalid?

    Checkpoint 5 of 6· Exam question

    A trading analyst has `trades(symbol, trade_ts, qty)` and `quotes(symbol, quote_ts, bid)`. Each trade must be paired with the latest quote for the same symbol at or before the trade time. This query fails with a syntax error: ``` SELECT t.symbol, t.trade_ts, q.bid FROM trades t ASOF JOIN quotes q ON t.symbol = q.symbol AND t.trade_ts >= q.quote_ts ``` What is the correct fix?

    Sources3

    4.Filtering at the right stage: WHERE, HAVING, QUALIFY

    After joining and combining, you filter down to what the business goal needs. Snowflake has a different filter for each stage of evaluation. WHERE filters source rows before grouping. HAVING filters the groups that GROUP BY produces, so its predicate can refer only to constants, GROUP BY expressions and aggregates. QUALIFY filters on window-function results, much as HAVING filters on aggregates. A common use is keeping the latest row per key. A query that uses QUALIFY must include at least one window function, in either the SELECT list or the QUALIFY predicate.

    Checkpoint 6 of 6· Put it in order

    Put these clauses in the order Snowflake typically evaluates them

    1. 1.GROUP BY
    2. 2.WHERE
    3. 3.HAVING
    4. 4.QUALIFY
    5. 5.ORDER BY

    Sources45

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.UNION keeps every row from both queries, so it is the right choice for appending two extracts.Why is that wrong?

      Plain UNION means UNION DISTINCT and removes duplicates. Use UNION ALL to keep them.

      Covered in Set operators: stacking and comparing result sets

    2. 2.An ASOF JOIN always returns the same row when several right-table rows share the closest timestamp.Why is that wrong?

      ASOF returns exactly one matching row. When rows tie, which one is returned can change from run to run.

      Covered in ASOF JOIN: the closest match in time

    3. 3.An ASOF JOIN drops left-table rows that have no earlier (or later) match, like an inner join.Why is that wrong?

      Unmatched left rows are kept, and the right-table columns are filled with NULLs.

      Covered in ASOF JOIN: the closest match in time

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “If the word JOIN is used without specifying INNER or OUTER, then the JOIN is an inner join.”
      ↩︎ Joins: which rows survive
      “omitting the ON clause results in a Cartesian product; every row of object_ref1 paired with every row of object_ref2.”
      ↩︎ Checkpoint
    2. 2.
      “UNION ALL combines rows by column position without duplicate elimination.”
      ↩︎ Set operators: stacking and comparing result sets
      “The INTERSECT operator has higher precedence than UNION [ALL] and MINUS (EXCEPT).”
      ↩︎ Set operators: stacking and comparing result sets
      “If a column exists in one input but not the other, it is filled with NULL values in the combined result set”
      ↩︎ Set operators: stacking and comparing result sets
      “The default is UNION DISTINCT (that is, combine rows by column position with duplicate elimination).”
      ↩︎ Exam trap 1
    3. 3.
      “the join finds a single row in the second (or right) table that has the closest timestamp value.”
      ↩︎ ASOF JOIN: the closest match in time
      “ASOF joins are not supported for joins with LATERAL table functions or LATERAL inline views.”
      ↩︎ ASOF JOIN: the closest match in time
      “The results are non-deterministic because any one of the tying rows might be returned.”
      ↩︎ Exam trap 2
      “When there is no match for a row in the left table, the columns from the right table are null-padded.”
      ↩︎ Exam trap 3
      “If no match is found for such values, the right table columns are null-padded.”
      ↩︎ Prediction
      “The comparison operator must be one of the following: >=, <=, >, <. The equals operator (=) is not supported.”
      ↩︎ Checkpoint
    4. 4.
      “QUALIFY does with window functions what HAVING does with aggregate functions and GROUP BY clauses.”
      ↩︎ Filtering at the right stage: WHERE, HAVING, QUALIFY
      “FROM WHERE GROUP BY HAVING WINDOW QUALIFY DISTINCT ORDER BY LIMIT”
      ↩︎ Checkpoint
    5. 5.
      “Filters rows produced by GROUP BY that do not satisfy a predicate.”
      ↩︎ Filtering at the right stage: WHERE, HAVING, QUALIFY

    Spotted a mistake, or was something unclear? Tell us.