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

    Domain 2 · Lesson 10/19

    Snowflake Aggregates, Window Functions, Ranking and Casting

    Given a dataset or scenario, work with and query the data.

    13 min read
    4.6% of exam
    9 sources
    Published 5 Oct 2026
    Docs as of 4 Oct 2026

    What you will be able to do

    • Choose between a GROUP BY aggregate and the same function used as a window function, based on the shape of the output you need
    • Write an OVER clause with PARTITION BY, ORDER BY and an explicit window frame, and add tiebreakers so the results are deterministic
    • Generate pseudo-random values with UNIFORM and RANDOM for pre-math steps such as assigning rows to test groups
    • Use TRY_CAST so that a string that won't convert becomes NULL and the query doesn't fail

    Key concept

    Window function (partition) — A window function calculates a value for every input row from a related group of rows, called a partition. It does not collapse each group into a single row the way GROUP BY does. The OVER clause defines the partition, the ordering and the frame.

    1.Aggregating with GROUP BY versus OVER

    Most work with a dataset starts with summarising it. In Snowflake, SUM, COUNT and AVG each come in two forms. The function name is the same in both, and the OVER clause tells them apart. With GROUP BY, each group of rows collapses to one output row. That is the right shape for a report of totals per category. With an OVER clause, the function still computes over a group of rows, but every input row stays in the result and carries the computed value next to it.

    A regular aggregate returns one row per menu categorysql
    SELECT menu_category,
        AVG(menu_cogs_usd) avg_cogs
      FROM menu_items
      GROUP BY 1
      ORDER BY menu_category;

    That query returns four rows: Beverage 0.60, Dessert 1.79, Main 6.11 and Snack 3.10. When the same AVG is used as a window function, every row in the table is returned. Each Beverage row shows 0.60000, and each Dessert row shows 1.79166. This gives you a simple way to validate an aggregate. The two forms must agree for each group, and the window form lets you check each detail row against its group value, such as the category average, in the same result.

    Checkpoint 1 of 8· Fill the gap

    Complete the query so that AVG returns the category average on every row instead of grouping the rows.

    SELECT menu_category,
        AVG(menu_cogs_usd) OVER( ?  BY menu_category) avg_cogs
      FROM menu_items
      ORDER BY menu_category
      LIMIT 15;

    Validation also means knowing how aggregates treat NULLs. AVG and SUM work on the non-NULL records only. COUNT has two behaviours: given specific columns it counts the non-NULL records, and otherwise it counts all records. Comparing COUNT(*) with COUNT(column) therefore shows how many NULLs a column holds. COUNT_IF counts the records that satisfy a condition. For large inputs, APPROX_COUNT_DISTINCT (alias HLL) estimates COUNT(DISTINCT ...) using HyperLogLog. It is deterministic for the same input, but the two results do not always match exactly: in the documentation example, 1024 distinct values were estimated as 1007. As a window function it does not support an ORDER BY or an explicit window frame.

    GROUPING SETS extends GROUP BY to compute several groupings in one statement. Grouping by (a) and (b) as separate sets is equivalent to a UNION ALL of two GROUP BY queries. The output contains NULLs in the columns that a given grouping does not use, and a NULL can also come from NULL data, so read those rows with care.

    Checkpoint 2 of 8· Check yourself

    A column has some NULL values. You want to find out how many rows have a NULL in it. Which comparison helps?

    Checkpoint 3 of 8· Exam question

    A dashboard query uses `SUM(amount) OVER (ORDER BY sale_date)` to build a running total. Several orders share the same `sale_date`, and every row of that day shows the same cumulative figure instead of growing row by row. Which change produces a true row-by-row running total?

    Sources1234

    2.Ordering, window frames and ranking

    With a partition on its own, every row in a partition gets the same value. Adding ORDER BY and a window frame inside OVER turns the calculation into a rolling one. The query below computes a moving average over the current row and the two rows that follow it in the same category. The query has a second ORDER BY at the end, which sorts the output. The two ORDER BY clauses are independent.

    A moving average with an explicit window frame and a tiebreaker columnsql
    SELECT menu_category, menu_price_usd, menu_cogs_usd,
        AVG(menu_cogs_usd) OVER(PARTITION BY menu_category
          ORDER BY menu_price_usd, menu_cogs_usd ROWS BETWEEN CURRENT ROW and 2 FOLLOWING) avg_cogs
      FROM menu_items
      ORDER BY menu_category, menu_price_usd, menu_cogs_usd
      LIMIT 15;

    menu_cogs_usd appears in the window's ORDER BY as a tiebreaker. Several items share the same price, and without a tiebreaker the 'following' rows could change from one run to the next. Two kinds of window function require ORDER BY: functions with an explicit frame, such as running totals and moving averages, and ranking functions such as CUME_DIST, RANK and DENSE_RANK. For example, ranking stores by monthly profit in descending order gives the most profitable store rank 1. Some functions treat an ORDER BY as an implied frame, so Snowflake recommends declaring the frame explicitly.

    Checkpoint 4 of 8· Check yourself

    In the moving-average output, the last Beverage row has menu_cogs_usd 0.65 and avg_cogs 0.65000. Why?

    So when an ORDER BY appears inside OVER, always name the columns. The ordinal shorthand that works in a query-level ORDER BY or in GROUP BY 1 has a different meaning inside OVER.

    Sources1

    3.Pre-math: randomization, ranking and grouping

    Pre-math calculations prepare values that later analysis uses: a rank for each row, a group label, or a random number for assigning rows to test cohorts. Ranking comes from the window functions above, and grouping comes from GROUP BY or PARTITION BY. Ranking functions need an ORDER BY inside OVER. DENSE_RANK returns the rank of a value within a group of values without gaps in the ranks, and ROW_NUMBER is the function to use when you need a gap-free numbering of rows. For random values, Snowflake provides two related functions. RANDOM returns raw pseudo-random 64-bit integers. UNIFORM converts a random source into a value within a range you specify.

    RANDOM compared with UNIFORM
    FunctionWhat it returnsNotes
    RANDOMPseudo-random 64-bit integersAccepts an optional seed so that a sequence can be repeated
    UNIFORM(min, max, gen)A uniformly distributed number in the inclusive range [min, max]gen is the raw random source, usually RANDOM(). Integer bounds give an integer result.
    Five random integers from 1 to 10 inclusivesql
    SELECT UNIFORM(1, 10, RANDOM()) FROM TABLE(GENERATOR(ROWCOUNT => 5));

    Checkpoint 5 of 8· Check yourself

    A developer writes UNIFORM(1, 10.0, RANDOM()) to assign each row a whole-number bucket from 1 to 10. What does it return?

    Checkpoint 6 of 8· Exam question

    A `salaries` table contains four employees earning 90, 90, 80 and 70. The analyst must list every employee who earns the second-highest distinct salary, which is 80, and the ranking must have no gaps after ties. Which filter returns the correct employee?

    Sources526

    4.Casting values to a consistent type

    Values usually need to be converted to one data type before they display consistently, for example strings that hold dates or numbers. Converting a data type is called casting. An explicit cast uses the CAST function, the :: operator, or a TO_ function such as TO_DOUBLE or TO_DATE. Snowflake also converts some values automatically, which is called implicit casting or coercion. For example, an INTEGER is coerced to VARCHAR so that 17 || '76' gives '1776'. Not all contexts support coercion, so cast explicitly when the type matters.

    Three explicit ways to cast a string to a DATEsql
    SELECT CAST('2022-04-01' AS DATE); SELECT '2022-04-01'::DATE; SELECT TO_DATE('2022-04-01');

    The semantics of CAST are the same as those of the matching TO_ function, and the :: operator is alternative syntax for CAST. When you give a target type a precision and scale, the target controls the display: if the scale is too small the value is rounded, so '9.8765' cast to NUMBER(5,2) becomes 9.88. If the precision is too small, or a value exceeds a VARCHAR length such as VARCHAR(4), the cast raises an error. The date and time TO_ functions also accept an optional format argument, with elements such as YYYY, MM, DD and HH24, to describe how a string is parsed or produced.

    Checkpoint 7 of 8· Check yourself

    A string '9.8765' is converted with CAST(varchar_value AS NUMBER(5,2)). What is the result?

    CAST and the :: operator raise an error if a value can't be converted. On a messy column, one bad value is enough to make the whole query fail. TRY_CAST performs the same conversion but returns NULL for values it can't convert. It has two limits: its input must be a string expression, and the target type must be VARCHAR, NUMBER, DOUBLE, BOOLEAN, DATE, an interval variation, TIME or one of the TIMESTAMP types. The TRY_TO_ functions, such as TRY_TO_DATE, are the error-handling versions of the TO_ functions. They are optimised for data with few conversion errors and can be much slower when many conversions fail.

    TRY_CAST returns NULL when a string is too long for the target typesql
    SELECT TRY_CAST('ABCD' AS CHAR(2));

    'ABCD' doesn't fit in CHAR(2), so the result is NULL. TRY_CAST('ABCD' AS VARCHAR(10)) returns ABCD. In the same way, '05-Mar-2016' converts to a TIMESTAMP, but '05/16' returns NULL.

    Checkpoint 8 of 8· Fill the gap

    A load contains date strings in several formats. Which function completes this statement so that it returns NULL instead of failing?

    SELECT  ? ('05/16' AS TIMESTAMP);

    Sources789

    Exam traps

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

    1. 1.OVER (PARTITION BY 1 ORDER BY 2) orders the window by the second column of the SELECT list.Why is that wrong?

      Inside a window's ORDER BY, 2 is treated as the constant 2. Name the columns explicitly.

      Covered in Ordering, window frames and ranking

    2. 2.TRY_CAST can safely replace CAST for any input type, including numeric columns.Why is that wrong?

      TRY_CAST accepts only string expressions, and only some target types. For other conversions, use CAST.

      Covered in Casting values to a consistent type

    Sources

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

    1. 1.
      “For a window function, the input is each row within a partition, and the output is one row per input row.”
      ↩︎ Aggregating with GROUP BY versus OVER
      “For an aggregate function, the input is a group of rows, and the output is one row.”
      ↩︎ Aggregating with GROUP BY versus OVER
      “Ranking window functions, such as CUME_DIST, RANK, and DENSE_RANK, which return information based on the “rank” of a row.”
      ↩︎ Ordering, window frames and ranking
      “If multiple rows have the same value for the ORDER BY columns, add additional columns as tiebreakers”
      ↩︎ Ordering, window frames and ranking
      “Snowflake recommends declaring window frames explicitly.”
      ↩︎ Ordering, window frames and ranking
      “A window function is an analytic SQL function that operates on a group of related rows known as a partition.”
      ↩︎ Key concept
      “The ORDER BY clause for window functions does not support the use of an ordinal position”
      ↩︎ Exam trap 1
      “The last row in a partition has no following rows so the average for the last Beverage row, for example, is the same”
      ↩︎ Checkpoint
      “In this context, 2 is interpreted as the constant 2; it does not refer to the second column in the query.”
      ↩︎ Prediction
    2. 2.
      “Returns either the number of non-NULL records for the specified columns, or the total number of records.”
      ↩︎ Aggregating with GROUP BY versus OVER
      “Returns the rank of a value within a group of values, without gaps in the ranks.”
      ↩︎ Pre-math: randomization, ranking and grouping
    3. 3.
      “Although the computation is an approximation, it is deterministic.”
      ↩︎ Aggregating with GROUP BY versus OVER
    4. 4.
      “GROUP BY GROUPING SETS((a), (b)) is equivalent to GROUP BY a UNION ALL GROUP BY b.”
      ↩︎ Aggregating with GROUP BY versus OVER
    5. 5.
      “Generates a uniformly-distributed pseudo-random number in the inclusive range [min, max].”
      ↩︎ Pre-math: randomization, ranking and grouping
      “RANDOM generates pseudo-random 64-bit integers. It accepts an optional seed that allows sequences to be repeated.”
      ↩︎ Pre-math: randomization, ranking and grouping
      “If either or both of min or max is a floating-point number, UNIFORM returns a floating-point number.”
      ↩︎ Checkpoint
    6. 6.
      “For examples that generate sequences without gaps, refer to SEQ1 / SEQ2 / SEQ4 / SEQ8 and ROW_NUMBER.”
      ↩︎ Pre-math: randomization, ranking and grouping
    7. 7.
      “returns a NULL value instead of raising an error when the conversion can not be performed.”
      ↩︎ Casting values to a consistent type
      “A special version of CAST , :: that is available for a subset of data type conversions.”
      ↩︎ Casting values to a consistent type
      “Only works for string expressions.”
      ↩︎ Exam trap 2
    8. 8.
      “In some situations, Snowflake converts a value to another data type automatically. This is called implicit casting or coercion.”
      ↩︎ Casting values to a consistent type
    9. 9.
      “If the scale is not sufficient to hold the input value, the function rounds the value.”
      ↩︎ Casting values to a consistent type

    Continue to page 2 of 2

    Enriching Snowflake Queries: Cross Joins, UNION, CTEs, Hierarchies and Sampling

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