createTable with dynamicTable
Creates a dynamic table in Snowflake. Dynamic tables are materialized views that automatically refresh based on changes to underlying data. This extends core Liquibase's createTable change type with dynamic table-specific features.
Note: Automatic rollback drops the table.
Known limitation: Snowflake snapshots created with Liquibase Secure 5.1 are incompatible with earlier versions due to enhanced object type detection for TABLES and VIEWS. Regenerate all snapshots with 5.1 after upgrading to avoid false differences in diff and diff-changelog operations.
Available attributes
Attribute | Type | Description | Required |
| String | Name of the catalog (database) | No |
| String | Name of the schema | No |
| String | Name of the dynamic table to create | Yes |
| String | Comment describing the table | No |
| String | Refresh lag (e.g., | Yes |
| String | Warehouse name for refresh operations | Yes |
| String | The AS SELECT query defining the table | Yes |
| Boolean | If true, replaces the existing with | No |
| Boolean | If true, only creates if the table doesn't exist* | No |
| Boolean | If true, creates a transient dynamic table | No |
| String | Refresh mode: | No |
| String | Initialization mode: | No |
| String | Comma-separated list of columns for clustering | No |
| Integer | Time Travel retention period (0-90 days) | No |
| Integer | Maximum extension beyond retention period | No |
| Boolean | If true, copies grants from existing table** | No |
| Boolean | If true, requires user context for refresh*** | No |
| String | Immutable WHERE clause for the query | No |
| String | Source table for backfilling data**** | No |
*replaceIfExists and ifNotExists are mutually exclusive.
**copyGrants requires replaceIfExists=true.
***Cannot use requireUser=truewith initialize=ON_CREATE.
****Cannot specify tagswhen using backfillFrom.
Nested elements
Element | Type | Description |
| Column definition | Column with Snowflake-specific properties (optional) |
| MapWrapper | Key-value pairs of tags to apply |
| RowAccessPolicy | Row-level security policy |
| AggregationPolicy | Privacy-preserving aggregation policy |
columnDynamicTable attributes
Optional element to define columns with Snowflake-specific properties like masking policies and collation.
Attribute | Type | Description |
| String | Column name |
| String | Snowflake data type |
| Boolean | Whether column allows NULL |
| String | Column collation (e.g., |
| String | Name of masking policy to apply |
| String | Column comment |
-- Basic dynamic table
CREATE DYNAMIC TABLE DAILY_SALES_SUMMARY
WITH
TAG (
environment = 'production',
owner = 'sales-analytics'
) TARGET_LAG = '5 minutes' WAREHOUSE = RD_WH COMMENT = 'Automatically refreshed summary of daily sales' AS
SELECT
DATE_TRUNC ('day', ORDER_TIMESTAMP) AS SALE_DATE,
SUM(ORDER_AMOUNT) AS TOTAL_SALES,
COUNT(*) AS ORDER_COUNT
FROM
ORDERS
WHERE
ORDER_STATUS = 'COMPLETED'
GROUP BY
DATE_TRUNC ('day', ORDER_TIMESTAMP);
-- Dynamic table with columns and features
CREATE DYNAMIC TABLE CUSTOMER_360_VIEW (
CUSTOMER_ID NUMBER (38, 0) NOT NULL,
CUSTOMER_NAME VARCHAR(200) COLLATE 'en-ci'
WITH
MASKING POLICY NAME_MASK COMMENT 'Customer name with masking',
TOTAL_PURCHASES NUMBER (18, 2)
)
WITH
TAG (
environment = 'production',
department = 'analytics'
) TARGET_LAG = '1 hour' WAREHOUSE = RD_WH REFRESH_MODE = INCREMENTAL INITIALIZE = ON_CREATE CLUSTER BY (CUSTOMER_ID) DATA_RETENTION_TIME_IN_DAYS = 7 COMMENT = 'Real-time customer data aggregation' AS
SELECT
c.CUSTOMER_ID,
c.CUSTOMER_NAME,
SUM(o.ORDER_AMOUNT) AS TOTAL_PURCHASES
FROM
CUSTOMERS c
JOIN ORDERS o ON c.CUSTOMER_ID = o.CUSTOMER_ID
GROUP BY
c.CUSTOMER_ID,
c.CUSTOMER_NAME;