A slowly changing dimension (SCD) is a data warehousing technique that tracks the complete history of an entity's changes, allowing you to query data state at any point in time. This topic walks through building an ETL process for an SCD table in DataWorks using the MaxCompute engine.
Prerequisites
A DataWorks workspace is created. For more information, see Create and manage workspaces.
A MaxCompute data source is added and is associated with the workspace. For more information, see Add a MaxCompute data source and associate the data source with a workspace.
Notes
In this tutorial, tables are created by running commands. In practice, you can create them visually in DataWorks. For more information, see Create and use MaxCompute tables.
You can also import the tasks in the DataStudio part of this tutorial with a single click using an ETL workflow template. After importing the template, go to the target workspace to perform subsequent operations such as task maintenance.
-
Only users with the workspace administrator role can import ETL templates into a target workspace. For more information about how to grant the workspace administrator role to an account, see Manage permissions on modules at the workspace level.
-
For more information about how to import an ETL workflow template, see Quickly experience an ETL workflow.
-
To quickly access the ETL workflow template, see SCD Implementation.
Scenarios
The SCD technique is ideal for data models with the following characteristics:
-
Large data volume.
-
Some fields in a table are updated.
Examples include user addresses, product descriptions, order statuses, and phone numbers.
-
You need to view historical snapshots of data for a specific point or period in time.
For example, you might need to check the status of an order at a past date or see how many times a user's information was updated within a specific period.
-
The proportion or frequency of data changes is low.
For example, imagine a table with 10 million members, but only about 100,000 are new or updated each day. Storing a full snapshot daily wastes significant storage by repeatedly saving unchanged information.
Key fields
An SCD table typically includes the following key fields:
|
Field |
Description |
|
Primary key |
Uniquely identifies each row of data. Also known as a surrogate key. |
|
Business key |
The key that uniquely identifies an entity in the source system. For example, a member ID. |
|
Attribute fields |
The entity attributes whose changes you want to track. For example, a member's nickname or phone number. |
|
Effective start date |
The time when a version of the data becomes valid. |
|
Effective end date |
The time when a version of the data becomes invalid. A high-value date, such as '9999-12-31', is often used to indicate that the record is currently active. |
|
Status flag |
Indicates whether the record is the most recent version. |
|
Version |
Identifies different historical versions of a record that share the same business key. |
This topic focuses on SCD implementation and does not cover table design in detail.
Example overview
-
Table design: This example uses two data tables.
-
Order source table:
ods_order_di. This table stores daily incremental data synchronized from the business database. It contains the following two fields:-
id: The order ID, which serves as the business key. -
status: The order status, which is the attribute to be tracked.
-
-
Order fact table (SCD table):
dwd_order. This table uses the SCD method to store all active and inactive data. It contains the following four fields:-
id: The order ID, which serves as the business key. -
status: The order status, which is the attribute being tracked. -
start_date: The effective start date. -
end_date: The effective end date.
-
-
-
SCD implementation logic.
-
This example uses an SCD table to record all changes in an e-commerce order's status (Created, Paid, Completed) from creation to its current state. For more information about the loading logic, see Data loading logic for the SCD table.
-
Task development: Preparation
Log on to the DataWorks console. In the target region, click in the left-side navigation pane. Select a workspace from the drop-down list and click Go to Data Development.
-
Create a workflow.
-
Hover over the
icon and click Create Workflow. -
In the Create Workflow dialog box, enter a Workflow Name and Description. For this example, name the workflow Tutorial_SCD_Implementation.
-
Click Create.
-
-
Create nodes.
In the directory tree on the left, double-click the workflow that you created in Step 2 to open its panel. Then, drag components from the left pane and connect them on the canvas to build the workflow.
This example uses two types of nodes: a zero load node and an ODPS SQL node.
-
The zero load node acts as the starting point for the entire SCD implementation, helping to manage the overall workflow.
-
The ODPS SQL node executes SQL tasks to load data into the SCD table.
-
-
Preview the task workflow.
This tutorial will create the following workflow. For clarity, this example uses the node group feature to group related nodes. The code for each node is provided in the subsequent steps.
The Tutorial_SCD_Implementation workflow contains the following nodes in order of dependency: the zero load node SCD_Implementation_Description → the ODPS SQL node ods_order_di (in the Prepare_Incremental_Table node group) → the ODPS SQL node dwd_order (in the Implement_SCD_Table node group) → the ODPS SQL node Query_SCD_Table. In DataStudio, after opening the workflow, drag the zero load node and ODPS SQL node from the node list on the left to the canvas and connect them to establish dependencies.
Task development: Prepare incremental data table
-
In the data preparation stage, you need to create two types of nodes:
-
Create a zero load node:
SCD_Implementation_Description. This node manages and describes the workflow. -
Create an ODPS SQL node:
ods_order_di. This node generates the source table for order transactions.
-
-
On the workflow canvas, connect the SCD_Implementation_Description zero load node to the ods_order_di SQL node within the Prepare_Incremental_Table node group to configure the dependency.
ods_order_di
-
Table data: The order source table contains the order ID (business key) and the order
statusfield to track changes. It stores daily new order data. -
On the editor tab of the
ods_order_dinode, use the following sample data from ods_order.csv to populate the ods_order_di source table.-
Test data in ods_order.csv.
id,gmt_create,gmt_modified,status,pt 210001,2023-10-04,2023-10-04,Created,2023-10-04 210002,2023-10-04,2023-10-04,Created,2023-10-04 210001,2023-10-04,2023-10-05,Paid,2023-10-05 210003,2023-10-05,2023-10-05,Created,2023-10-05 210004,2023-10-05,2023-10-05,Created,2023-10-05 210001,2023-10-04,2023-10-06,Completed,2023-10-06 210002,2023-10-04,2023-10-06,Paid,2023-10-06 210004,2023-10-05,2023-10-06,Paid,2023-10-06 210005,2023-10-06,2023-10-06,Created,2023-10-06 -
When inserting test data, add it to the corresponding partition (pt) as follows:
-- Note: For testing purposes, we insert three days of new data into partitions '2023-10-04', '2023-10-05', and '2023-10-06' at once. -- In a real-world scenario, you would typically update only the partition for the current business date. This can be done by setting the partition date as a scheduling parameter variable. INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-04') VALUES (210001,DATE'2023-10-04',DATE'2023-10-04','Created') ,(210002,DATE'2023-10-04',DATE'2023-10-04','Created') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-05') VALUES (210001,DATE'2023-10-04',DATE'2023-10-05','Paid') ,(210003,DATE'2023-10-05',DATE'2023-10-05','Created') ,(210004,DATE'2023-10-05',DATE'2023-10-05','Created') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-06') VALUES (210001,DATE'2023-10-04',DATE'2023-10-06','Completed') ,(210002,DATE'2023-10-04',DATE'2023-10-06','Paid') ,(210004,DATE'2023-10-05',DATE'2023-10-06','Paid') ,(210005,DATE'2023-10-06',DATE'2023-10-06','Created') -
The complete code is as follows:
-- 1. Create the ods_order_di source table to store daily new order data. -- Note: For clarity, the order creation and modification time fields in this example are at a daily granularity. It is assumed that an order is processed only once per day. -- In real-world scenarios, time fields usually have a finer granularity, and multiple operations may occur on an order within a single day. CREATE TABLE IF NOT EXISTS ods_order_di ( id BIGINT COMMENT 'Order ID' ,gmt_create DATE COMMENT 'Creation time, in yyyy-mm-dd format' ,gmt_modified DATE COMMENT 'Update time, in yyyy-mm-dd format' ,`status` STRING COMMENT 'Status' ) COMMENT 'Source table for transaction orders' PARTITIONED BY ( pt STRING COMMENT 'Date, in yyyy-mm-dd format' ) LIFECYCLE 7 ; -- 2. Initialize historical new order data. -- Note: For testing purposes, we insert three days of new data into partitions '2023-10-04', '2023-10-05', and '2023-10-06' at once. -- In a real-world scenario, you would typically update only the partition for the current business date. This can be done by setting the partition date as a scheduling parameter variable. INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-04') VALUES (210001,DATE'2023-10-04',DATE'2023-10-04','Created') ,(210002,DATE'2023-10-04',DATE'2023-10-04','Created') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-05') VALUES (210001,DATE'2023-10-04',DATE'2023-10-05','Paid') ,(210003,DATE'2023-10-05',DATE'2023-10-05','Created') ,(210004,DATE'2023-10-05',DATE'2023-10-05','Created') ; INSERT OVERWRITE TABLE ods_order_di PARTITION (pt = '2023-10-06') VALUES (210001,DATE'2023-10-04',DATE'2023-10-06','Completed') ,(210002,DATE'2023-10-04',DATE'2023-10-06','Paid') ,(210004,DATE'2023-10-05',DATE'2023-10-06','Paid') ,(210005,DATE'2023-10-06',DATE'2023-10-06','Created')
-
Task development: Implement the SCD table
-
Create an ODPS SQL node:
dwd_order. This node generates the order fact table. -
Connect the SCD_Implementation_Description zero load node to the ods_order_di ODPS SQL node in the Prepare_Incremental_Table group. Then, connect ods_order_di to the dwd_order ODPS SQL node in the Implement_SCD_Table group.
dwd_order
-
Table data: The order fact table (SCD table) stores all active and inactive data. It includes the effective start date (start_date), effective end date (end_date), business key ID, and the
statusfield for tracking order status changes. -
On the editor tab of the
dwd_ordernode, enter the following sample code:-- 1. Create the order fact table to store all historical data using the SCD method. -- Note: The SCD table adds lifecycle fields: start_date (effective date) and end_date (expiration date). -- An end_date of '9999-12-31' indicates that the record is currently valid. CREATE TABLE IF NOT EXISTS dwd_order ( ID BIGINT COMMENT 'Order ID' ,gmt_create DATE COMMENT 'Creation time, in yyyy-mm-dd format' ,gmt_modified DATE COMMENT 'Update time, in yyyy-mm-dd format' ,`status` STRING COMMENT 'Status' ,start_date DATE COMMENT 'Effective date, in yyyy-mm-dd format' ,end_date DATE COMMENT 'Expiration date, in yyyy-mm-dd format. 9999-12-31 indicates the record is active.' ) COMMENT 'Fact detail table for transaction orders (SCD table)' ; -- 2. SCD storage logic: Insert all new or updated data from ods_order_di for the current business date into dwd_order as new, valid records. -- Update the previously active records in dwd_order that have been changed to be inactive. INSERT OVERWRITE TABLE dwd_order SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM ( SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date -- 2.3 Support re-runs: Use a window function to partition by id, gmt_create, gmt_modified, and `status`. Sort by end_date in descending order within the partition and take only the first row. ,ROW_NUMBER() OVER (DISTRIBUTE BY id,gmt_create,gmt_modified,`status` SORT BY end_date DESC ) AS row_num FROM ( -- 2.1 Invalidate old records: For records in dwd_order that have been updated, change their status from active to inactive. SELECT a.id AS id ,a.gmt_create AS gmt_create ,a.gmt_modified AS gmt_modified ,a.`status` AS `status` ,a.start_date AS start_date ,CASE WHEN b.id IS NOT NULL -- AND CAST(a.end_date AS STRING) > '${biz_date}' THEN DATE'${biz_date}' AND CAST(a.end_date AS STRING) == '9999-12-31' THEN DATE'${biz_date}' ELSE a.end_date END AS end_date -- 2.4 Note on scheduling dependencies: Because the calculation for dwd_order on the current day depends on its own output from the previous day, we configure a dependency on "Instances of Current Node" in the Properties > Cross-cycle Dependency section. FROM dwd_order AS a LEFT JOIN ( SELECT id ,gmt_create ,gmt_modified ,`status` FROM ods_order_di WHERE pt == '${biz_date}' ) b ON a.id == b.id UNION ALL -- 2.2 Insert new and updated records: Insert all new or updated records from ods_order_di for the current business date into dwd_order as active records. SELECT id ,gmt_create ,gmt_modified ,`status` ,DATE'${biz_date}' AS start_date ,DATE'9999-12-31' AS end_date FROM ods_order_di WHERE pt == '${biz_date}' ) ) with_row_num_tb -- Support re-runs WHERE row_num == 1 ; -
Configure scheduling. The following are the key configurations. You can keep the default values for other parameters.
-
Scheduling Parameter: In the section, click Load Parameters in Code to automatically generate the parameter configuration. In the Parameter Value field, enter
$[yyyy-mm-dd-1]. For more information about supported formats for scheduling parameters, see Supported formats of scheduling parameters.NoteYou can also click Define by expression to manually add the scheduling parameter
biz_date=$[yyyy-mm-dd-1] -
Configure the Cross-cycle Scheduling Dependency. The data processing for the dwd_order table on a given day depends on its own output from the previous day. To ensure data accuracy and continuity, you must configure a self-dependency.
In the section, select the This node checkbox. This ensures that the data for the current cycle is loaded only after the data from the previous cycle has been successfully processed. This ensures the integrity of the data processing flow.
-
SCD table data loading logic
-
Existing active records in the dwd_order table that are updated on the current business date are marked as inactive.
-
All new records from the ods_order_di table for the current business date are inserted into the dwd_order table as active records.
The following steps use the data for the business date of October 5 as an example:
-
Original data: On October 4, the SCD table contains a record for order ID
210001with the statusCreated. -
Status change: On October 5, the status of this order is updated to
Paid. -
Data comparison logic:
-
Join all active historical data from the SCD table on October 4 with the new data from the
2023-10-05partition of the incremental table. -
Check for status updates: If the order with ID
210001exists in the SCD table on October 4 with an end_date of9999-12-31(meaning it is active), and it also appears in the2023-10-05partition of the incremental table, its status has been updated.
-
-
Update process:
-
The end_date of the original record in the SCD table is updated from
9999-12-31to the current business date,2023-10-05. -
If the order ID does not appear in the
2023-10-05partition of the incremental table, it means there is no update, and the original record remains unchanged.
-
-
Data overwrite:
After completing these steps, the processed historical data from the SCD table and all new data from the incremental table are written back into the SCD table, producing the final SCD data for October 5.

Task development: Use the SCD table
-
At this stage, create an ODPS SQL node that depends on all the preceding tasks:
-
A node named
Query_SCD_Table.
-
-
Connect the nodes to establish the full dependency chain: the SCD_Implementation_Description zero load node connects to the ods_order_di SQL node, which then connects to the dwd_order SQL node, and finally connects to the Query_SCD_Table SQL node. These connections establish the upstream and downstream dependencies.
-
Query node: After the data loading is complete, create a query node and write SQL queries to view the SCD storage results.
-
On the editor tab for the
Query_SCD_Tablenode, enter the following sample code:-- 1. Use the SCD table -- 1.1 To get all current and valid data, query the records from the dwd_order table where end_date is '9999-12-31'. SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM dwd_order WHERE end_date == DATE'9999-12-31' ORDER BY id DESC LIMIT 100 ; -- 1.2 To get all historical snapshots for a specific order, query the dwd_order table by its ID and sort the results by end_date. SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM dwd_order WHERE id == 210001 ORDER BY end_date DESC LIMIT 100 ; -- 1.3 Query all data in the dwd_order table and sort it by order ID and end_date in descending order. SELECT id ,gmt_create ,gmt_modified ,`status` ,start_date ,end_date FROM dwd_order ORDER BY id,end_date DESC LIMIT 100 ;
Run the workflow
Because the test case inserts three days of data at once into partitions "2023-10-04", "2023-10-05", and "2023-10-06", you must perform a data backfill in the production environment to process all business dates. Follow these steps in Operation Center.
-
Commit tasks.
-
Click the
icon in the toolbar. -
In the Submission dialog box, select the nodes you want to commit and enter a Change Description.
-
Click OK. When the Operation Completed message appears, the tasks are committed successfully.
If you are using a workspace in standard mode, click Deploy in the upper-right corner after a successful commit. For more information, see Deploy tasks.
-
-
Go to Operation Center.
After the tasks are deployed, click Operation Center in the upper-right corner.
Alternatively, go to the editor page of the Tutorial_SCD_Implementation workflow and click Go to Operation Center in the toolbar to go to the Operation Center page.
-
Run a data backfill instance for the Auto Triggered Node.
-
In the left-side navigation pane, choose . On the Periodic tasks page, click the root node of the Tutorial_SCD_Implementation workflow, which is
SCD_Implementation_Description. -
Right-click the
SCD_Implementation_Descriptionnode and choose . -
In the Retroactive Instance dialog box, set the Business Date to 2023-10-04~2023-10-06. In the Nodes section, select all nodes, and click Determine. You are automatically redirected to the Data Backfill Instance page.
-
Click Refresh until all SQL tasks have run successfully.
-
To avoid incurring ongoing charges after completing the tutorial, you can set the scheduling validity period for the nodes or freeze the root node of the workflow (the zero load node SCD_Implementation_Description).
Query results
After all SQL tasks have run in Operation Center, you can view the results in the log:
-
On the Backfill Instance page, find the Query_SCD_Table node in the instance list. In the Operation column, click DAG, then click View Log.
-
Go to the log details page for the Query_SCD_Table node. In the section, you can view the run results.
After the node runs successfully, the Summary area in the log displays the query results. The result table shows status changes (Created, Paid, Completed) for orders 210001 to 210005 over different time periods, with columns for
id,gmt_create,gmt_modified,status,start_date, andend_date. Each order has multiple rows, demonstrating the historical snapshot capability of the SCD table.
After all SQL tasks have run in Operation Center, you can also return to DataStudio and run the Query_SCD_Table node independently to view the SCD storage results.
Click Run in the toolbar to execute the SQL. The query uses WHERE end_date == DATE'9999-12-31' to filter for all currently active data in the dwd_order table. After the run completes, view the active record for each order in the results panel below.
Appendix: Using an ETL workflow template
This tutorial is available as a built-in ETL workflow template in DataWorks. Import the template by following these steps:
-
Log on to the DataWorks console. In the left-side navigation pane, click to go to the ETL Workflow Template page.
-
On the ETL Workflow Template page, select the SCD Implementation workflow. Click View Details to go to the template page, then click Load Template.
-
In the Load Template dialog box, select the target Workspace. In the MaxCompute Configuration section, select a data source from the Data Source Name drop-down list. Click OK to load the template.
Release resources
After testing, release the resources generated by this tutorial. For more information, see the following documents:
-
Delete tables: Delete MaxCompute tables in batches.
-
Decommission tasks: Decommission a task.
Related documents
-
To learn about virtual node operations, see Virtual Node.
-
To learn about the ODPS SQL node for MaxCompute, see Create and manage a MaxCompute node.
-
To learn more about developing ODPS SQL tasks, see Develop an ODPS SQL task.
-
To learn more about scheduling cycle tasks in the Operations Center, see Basic O&M operations for cycle tasks.