Create a dynamic table¶
This tutorial shows how to create a dynamic table and connect it into a two-table pipeline.
For the full syntax reference, see CREATE DYNAMIC TABLE.
Note
This tutorial assumes you know how to create tables and write SELECT queries. If you are new to Snowflake, complete the Snowflake in 20 minutes tutorial first.
The examples on this page use CREATE OR REPLACE, which drops and recreates objects if they already exist. Run them in a test database and schema to avoid overwriting production data.
Before you start¶
Make sure you have USAGE on a warehouse and schema, and CREATE DYNAMIC TABLE on the target schema. For full requirements, see Dynamic table access control.
Set up base tables¶
Create a base table and a dimension table, then insert sample data so you can copy and run every example on this page:
The downstream dynamic table in this tutorial also joins to a dimension table. Create that table now:
Tip
Primary keys are optional but improve incremental refresh performance. Both base tables declare a PRIMARY KEY with RELY so Snowflake can identify changed rows during refresh. For more information, see primary key best practices.
Create a dynamic table¶
Run the following statement to create a dynamic table that filters out returned orders and computes a line total for each row:
Note
If you omit REFRESH_MODE, it defaults to AUTO and Snowflake selects incremental or full refresh at creation time. This tutorial sets REFRESH_MODE = INCREMENTAL explicitly so the refresh mode is deterministic across recreations. For details on how each mode works, see Dynamic table refresh modes.
The key parameters beyond the table name are:
- TARGET_LAG: The freshness goal for the data. Snowflake schedules refreshes to keep data no more than 10 minutes behind the source. Actual staleness can exceed this depending on refresh runtime.
- WAREHOUSE: The compute resource that runs scheduled refreshes.
- REFRESH_MODE: Determines how Snowflake processes changes.
INCREMENTALreprocesses only changed rows.FULLrefreshes the entire table from scratch on every refresh. See the note that follows for guidance.
The dynamic table initializes immediately after creation by default.
Note
Set REFRESH_MODE explicitly for production workloads to avoid unexpected refresh mode changes. See choosing a refresh mode for details.
Verify with SHOW DYNAMIC TABLES¶
The CREATE statement does not report the resolved refresh mode. Run SHOW DYNAMIC TABLES to confirm the mode and verify that scheduling_state is RUNNING:
Check that refresh_mode shows the mode you expect and scheduling_state is RUNNING.
Add a downstream dynamic table¶
A downstream dynamic table reads from another dynamic table instead of a base table. This
downstream table joins dt_orders with dim_customers and aggregates daily revenue by region and
segment:
Snowflake tracks the dependency between dynamic tables and refreshes them in the correct order
automatically (see pipeline ordering), so dt_orders is always refreshed before dt_orders_daily.
Note
The TARGET_LAG of a downstream dynamic table must be greater than or equal to the TARGET_LAG of
the dynamic table it depends on. In this example, dt_orders_daily (30 minutes) is greater than
dt_orders (10 minutes). For more information, see Set the target lag for a dynamic table.
Query the pipeline output¶
dt_orders excludes the returned order (order 1005), so it does not appear in the
aggregated results.
To visualize the pipeline you created, navigate to Transformation » Dynamic tables in Snowsight, select any table in the pipeline, and open the Graph tab. For more on pipeline visualization, see View the pipeline graph in Snowsight.
Check refresh history¶
After verifying the query output, confirm that refreshes are completing successfully:
For more ways to monitor refresh status, set up alerts, and troubleshoot failures, see Monitor dynamic tables.
Troubleshoot common issues¶
Dynamic table shows no data: If your dynamic table was created successfully but returns no rows, verify that the query returns data when run as a standalone SELECT. A common cause is a WHERE clause that filters out all current rows. Also check:
- If the table was created by a different role, access or masking policies may filter data differently for your current role.
- Verify that you have the correct warehouse, database, and schema context and that you have SELECT privilege on the base tables.
Refresh mode is FULL instead of INCREMENTAL: If SHOW DYNAMIC TABLES shows refresh_mode as
FULL when you expected INCREMENTAL, your definition contains a SQL feature that doesn’t support
incremental refresh. Check the refresh_mode_reason column for details, and see
Supported queries for dynamic tables for the full list of supported query patterns.
Clean up¶
If you created these objects for testing purposes, drop them to avoid ongoing warehouse costs from scheduled refreshes:
What’s next¶
- Choose a target lag for your workload: Set the target lag for a dynamic table
- Understand incremental versus full refresh: Dynamic table refresh modes
- Monitor refresh history and troubleshoot failures: Monitor dynamic tables