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

    Domain 1 · Lesson 2/19

    Snowflake Data Discovery: Context, Metadata, Statistics and Granularity

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

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

    What you will be able to do

    • Set and verify session context with USE and the context functions
    • Read table metadata and Snowflake-maintained statistics with SHOW and DESCRIBE
    • Profile columns with aggregate functions and SAMPLE to confirm that the elements a business metric needs are present
    • Choose the level of granularity a result needs with GROUP BY and GROUP BY ROLLUP
    • Break a business goal, stated as a BI report or a SQL analysis, into the elements, granularity and table joins it requires

    Key concept

    Discovery before transformation — Before you design any transformation, find out what the data actually contains: which objects exist, which columns and types they have, how many rows they hold, and the grain at which they record facts. Snowflake exposes this through metadata commands (SHOW, DESCRIBE) and through ordinary aggregate queries.

    1.Set your context first: USE and the context functions

    Discovery queries only make sense when you know where they run. An unqualified table name is resolved against the session's current database and schema, and the warehouse you are using is the one that gets billed. The USE command sets that context. It covers five things, each with its own variant: USE ROLE, USE SECONDARY ROLES, USE WAREHOUSE, USE DATABASE and USE SCHEMA.

    USE changes state and returns nothing you can inspect. To confirm what is active, call the context functions. Run this check whenever a discovery query returns an unexpected "object does not exist" error or an empty result. The usual cause is that the query ran under a different role or schema than you thought.

    Reading back the current session context with context functionssql
    SELECT CURRENT_ROLE(),
           CURRENT_SECONDARY_ROLES(),
           CURRENT_WAREHOUSE(),
           CURRENT_DATABASE(),
           CURRENT_SCHEMA();

    Checkpoint 1 of 6· Check yourself

    You ran USE DATABASE and USE SCHEMA earlier in a long worksheet. What is the documented way to confirm which database and schema are active now?

    Sources1

    2.Reading metadata and statistics: SHOW and DESCRIBE

    With the context set, two command families tell you what exists. Neither one reads table data.

    SHOW <objects> lists every object of one type, such as SHOW DATABASES, SHOW WAREHOUSES, SHOW GRANTS or SHOW TABLES. Each row carries common properties (name, creation timestamp, owning role, comment) plus properties specific to that object type. For tables, Snowflake also maintains statistics that answer "how big is this?" without a scan. In SHOW TABLES output, the rows column gives the row count and the bytes column gives the number of bytes that a full-table scan would read. That byte figure may differ from the physical storage on disk. The output also includes cluster_by, the clustering key if one is defined. Row counts are not available for external tables, which return NULL in the rows column.

    DESCRIBE <object>, which can be abbreviated to DESC, returns the details of a single object. For a table, the default (TYPE = COLUMNS) lists one row per column. DESCRIBE TABLE and DESCRIBE VIEW are interchangeable for this purpose. What DESCRIBE TABLE does not show is the table's object parameters. To see those, run SHOW PARAMETERS IN TABLE.

    The output of either command can be queried like a result set, using the pipe operator (->>) or RESULT_SCAN. The output column names are lowercase, so you must double-quote them, for example SELECT "type".

    Key DESCRIBE TABLE (TYPE = COLUMNS) output columns and what they tell you during discovery
    Output columnWhat it reports
    nameName of the column in the table
    typeData type of the column, including any collation specification
    kindCOLUMN for regular columns or VIRTUAL for virtual columns defined by an expression
    null?Whether the column accepts NULL values (Y or N)
    defaultThe default value for the column, if any (otherwise NULL)
    primary key / unique keyWhether the column is (part of) the primary key, or has a UNIQUE constraint (Y or N)
    policy nameThe masking policy set directly on the column, if any

    Checkpoint 2 of 6· Check yourself

    Before profiling a table you want to know roughly how many rows it holds and how many bytes a full scan would read, without running a query against the data. Which command gives you both?

    Checkpoint 3 of 6· Exam question

    A retailer stores EMEA and APAC orders in two tables with identical column lists, `orders_emea` and `orders_apac`. An analyst must stack them to count every order line in discovery, and two genuine order lines can be identical in all columns. Which approach returns the correct row count?

    Sources234

    3.Profiling the elements a business goal needs

    Metadata tells you a column exists. It does not tell you whether the column is populated well enough to support a metric. To find that out, query the data itself. Aggregate functions are the main profiling tool, because they collapse many rows into one figure: COUNT, COUNT_IF, MIN, MAX, AVG, MEDIAN, MODE and STDDEV for shape, and APPROX_COUNT_DISTINCT (an alias for HLL) for estimating cardinality.

    Be careful with NULLs when you read those numbers.

    Because aggregates skip NULLs, an average can look healthy while hiding a sparsely filled column. If every input is NULL, the aggregate returns NULL. A multi-column COUNT(col1, col2) skips any row where one of the listed columns is NULL. GROUP BY behaves differently: it keeps those rows and groups NULL as a value of its own.

    On a very large table you can profile a subset first. SAMPLE (synonym TABLESAMPLE) returns randomly sampled rows, either as a fraction of the table or as a fixed number of rows. The default method is BERNOULLI, which keeps each row with probability p/100. SYSTEM (also called BLOCK) samples whole blocks of rows instead. You can specify a seed to make a fraction-based sample repeatable.

    The last question is whether the available tables contain every element the business goal requires. The requirement may arrive as a BI report you have to rebuild or as a SQL analysis you have to reproduce. Either way, break it into the same three parts: the measures it reports, the dimensions it breaks those measures down by, and the level of data granularity required, meaning what one result row represents. Snowflake's semantic views use the same vocabulary. They call the parts metrics and dimensions, and they require the logical table for a dimension to have an equal or lower level of granularity than the logical table for the metric.

    Use the statistics maintained by Snowflake to size each candidate table: the rows and bytes columns in SHOW TABLES, or ROW_COUNT in the Information Schema TABLES view. Then map each required element to the table that holds it. That mapping tells you which transformations are required. The documentation's sales example shows how this works. Gross revenue per product needs only retail_price and quantity, which are both in sales. Net profit also needs wholesale_price, which exists only in products, so the profit metric requires a table join. When a report needs the same metric at several levels, you do not need one query per level. As the documentation puts it, you could create separate reports, but it is more efficient to scan the data once.

    Profit per product requires an element (wholesale_price) from a second tablesql
    SELECT p.product_ID, SUM((s.retail_price - p.wholesale_price) * s.quantity) AS profit
      FROM products AS p, sales AS s
      WHERE s.product_ID = p.product_ID
      GROUP BY p.product_ID;

    Once you know a join is required, the join type decides which rows survive. An INNER JOIN produces a row only where the ON condition matches. A LEFT OUTER JOIN also keeps every left-table row that has no match, and the right-table columns in those rows contain NULL. RIGHT OUTER JOIN does the same for the right table, and FULL OUTER JOIN keeps unmatched rows from both sides. If you leave out the join condition (an INNER JOIN without ON, or a comma join without a WHERE clause), the result is a Cartesian product, which is usually a mistake.

    So before you choose a join, check whether every fact row has a match. In the query above, a sale whose product_ID is missing from products would silently drop out of the profit report.

    Checkpoint 4 of 6· Check yourself

    A revenue report must keep every row of the sales table, even sales whose product_ID has no matching row in products. Which join, with sales on the left, does that?

    Checkpoint 5 of 6· Check yourself

    A table has four rows for (x, y): (1, 2), (3, NULL), (NULL, 6), (NULL, NULL). What does SELECT COUNT(x, y) return?

    Sources5678910

    4.Deciding the level of granularity

    Granularity means what a single result row represents: one sale, one product, one city or one state. GROUP BY is how you set it. The columns you group by become the grain, and every other column must be aggregated. Grouping the sample sales table by product_ID gives one row per product. Grouping the same table by state and city gives one row per city within its state. GROUP BY ALL groups by every SELECT item that is not an aggregate.

    The same sales data aggregated at state-and-city grainsql
    SELECT state, city, SUM(retail_price * quantity) AS gross_revenue
      FROM sales
      GROUP BY state, city;
    
    +-------+---------+---------------+
    | STATE |   CITY  | GROSS REVENUE |
    +-------+---------+---------------+
    |   CA  | SF      |            22 |
    |   CA  | SJ      |            44 |
    |   FL  | Miami   |            80 |
    |   FL  | Orlando |           160 |
    |   PR  | SJ      |           320 |
    +-------+---------+---------------+

    Look at SJ. California and Puerto Rico both have a city with that name. A query grouped by city alone would merge them into one row, which is the wrong grain for a per-city report. If the business needs several levels at once (city, state and a grand total), GROUP BY ROLLUP (state, city) returns all of them in one scan. List the most significant level first. In the rollup rows, the columns that were rolled up show NULL. The GROUPING function tells those NULLs apart from NULLs that are really in the data.

    Checkpoint 6 of 6· Check yourself

    A report needs revenue per city. The data contains two different cities that are both named SJ, in different states. Which approach keeps them separate, as the documentation recommends?

    Sources119

    Exam traps

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

    1. 1.DESCRIBE TABLE shows everything about a table, including its object parameters.Why is that wrong?

      DESCRIBE TABLE shows columns, or stage properties with TYPE = STAGE. To see object parameters you need SHOW PARAMETERS IN TABLE.

      Covered in Reading metadata and statistics: SHOW and DESCRIBE

    2. 2.COUNT(col1, col2) counts every row where at least one of the columns has a value.Why is that wrong?

      A multi-column aggregate skips any row in which any of the listed columns is NULL. GROUP BY, by contrast, keeps those rows.

      Covered in Profiling the elements a business goal needs

    3. 3.The ON clause is optional, so a join without one simply matches rows on their common columns.Why is that wrong?

      Except for NATURAL JOIN, leaving out the ON clause pairs every row of one table with every row of the other. The resulting Cartesian product is usually a user error.

      Covered in Profiling the elements a business goal needs

    Sources

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

    1. 1.
      “Specifies the role, warehouse, database, or schema to use for the current session.”
      ↩︎ Set your context first: USE and the context functions
      “To view the current role, secondary roles, database, schema, and warehouse for the session, use the corresponding context functions.”
      ↩︎ Checkpoint
    2. 2.
      “Number of rows in the table. Returns NULL for external tables.”
      ↩︎ Reading metadata and statistics: SHOW and DESCRIBE
      “Number of bytes that will be scanned if the entire table is scanned in a query.”
      ↩︎ Checkpoint
    3. 4.
      “You must use double-quoted identifiers because the output column names for SHOW commands are in lowercase.”
      ↩︎ Reading metadata and statistics: SHOW and DESCRIBE
      “This command does not show the object parameters for a table. Instead, use SHOW PARAMETERS IN TABLE.”
      ↩︎ Exam trap 1
    4. 5.
      “Returns a subset of rows sampled randomly from the specified table.”
      ↩︎ Profiling the elements a business goal needs
      “You can specify a seed to make the sampling deterministic.”
      ↩︎ Profiling the elements a business goal needs
    5. 6.
      “If all of the values passed to the aggregate function are NULL, then the aggregate function returns NULL.”
      ↩︎ Profiling the elements a business goal needs
      “This behavior differs from the behavior of GROUP BY, which does not discard rows when some columns are NULL”
      ↩︎ Exam trap 2
      “In both the numerator and the denominator, only the two non-NULL values are used.”
      ↩︎ Prediction
      “In these instances, the aggregate function ignores a row if any individual column is NULL.”
      ↩︎ Checkpoint
    6. 7.
      “the logical table for the dimension must have an equal or lower level of granularity than the logical table for the metric”
      ↩︎ Profiling the elements a business goal needs
    7. 9.
      “You could create separate reports to get that information, but it is more efficient to scan the data once.”
      ↩︎ Profiling the elements a business goal needs
      “produces aggregated rows at multiple levels of a hierarchy (in addition to the detailed grouped rows)”
      ↩︎ Deciding the level of granularity
      “create a unique ID for each city and use the ID rather than the name in the query.”
      ↩︎ Checkpoint
    8. 10.
      “The result of the inner join is augmented with a row for each row of o1 that has no matches in o2.”
      ↩︎ Profiling the elements a business goal needs
      “omitting the ON clause results in a Cartesian product; every row of object_ref1 paired with every row of object_ref2.”
      ↩︎ Exam trap 3
    9. 11.
      “Groups rows with the same group-by-item expressions and computes aggregate functions for the resulting group.”
      ↩︎ Deciding the level of granularity

    Also cited

    Continue to page 2 of 2

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

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