< Previous Module - Home - Next Module >
45 minutes
- Lab environment deployed
- Module 1A complete
- Module 1B complete
In this module, we will setup a Synapse Pipeline to incrementally load data from our raw layer (CSV), into our curated layer (Delta Lake) as a SCD Type 2 dimension table.
Pipeline
flowchart LR
a1[Data flow\nincrementalLoad]
df01[Source\nrawCustomer]
df02[Exists\nnewRecords]
df03[Exists\nexistingRecords]
df04[Derived column\naddHash]
df05[Exists\nchangedRecords]
df06[Union\nunionNewActive]
df07[Alter row\nmarkAsInsert]
df08[Surrogate key\naddTempKey]
df09[Join\njoinMaxSurrogateKey]
df10[Derived column\nscdColumns]
df11[Select\ndropTempColumns]
df12[Union\nunionResults]
df13[Sink\nsinkCustomer]
df14[Source\ndimCustomer]
df15[Filter\nactiveCustomers]
df16[Aggregate\nmaxSurrogateKey]
df17[Derived column\naddHashDim]
df18[Exists\nobsoleteRecords]
df19[Alter row\nmarkAsUpdate]
df20[Derived column\nscdColumnsObsolete]
df21[Select\ndropTempColumns2]
param((fileName))
param-.->a1
ds1[(Data Lake\nraw)]
ds2[(Data Lake\ncurated)]
ds3[(Data Lake\ncurated)]
ds1-."01-raw/wwi/customers/$fileName\nCSV".->df01
df13-."03-curated/wwi/customers\nDelta Lake".->ds2
ds3-."03-curated/wwi/customers\nDelta Lake".->df14
subgraph p["Pipeline (C3 - pipelineDimIncrementalLoad)"]
a1
end
a1-.->df
subgraph df["Dataflow (dataFlowDimIncrementalLoad)"]
df01-->df02
df01-->df03
df02-->df06
df03-->df04
df04-->df05
df05-->df06
df06-->df07
df07-->df08
df08-->df09
df09-->df10
df10-->df11
df11-->df12
df12-->df13
df14-->df15
df15-->df16
df16-->df09
df15-->df17
df17-->df18
df17-->df05
df18-->df19
df19-->df20
df20-->df21
df21-->df12
df05-->df18
df15-->df02
df15-->df03
end
- New customer data (rawCustomer)
- Existing customer data (dimCustomer)
- Filtered existing customer data (activeCustomer)
- Identify net new customers (newRecords)
- Identify existing customers (existingRecords)
- Add hash fingerprint to existing customers from new data (addHash)
- Add hash fingerprint to existing customers from existing data (addHashDim)
- Identify existing customers with changed values (changedRecords)
- Union newRecords and changedRecords (unionNewActive)
- Mark these rows as INSERT (markAsInsert)
- Add an incremental key (addTempKey)
- Calculate current maximum surrogate key from existing data (maxSurrogateKey)
- Join two data streams addTempKey and maxSurrogateKey (joinMaxSurrogateKey)
- Set value for SCD columns such as CustomerSK, IsActive, ValidFrom, ValidTo (scdColumns)
- Drop temporary columns such as Hash, TempKey, and MaxCustomerSK (dropTempColumns)
- Identify obsolete customer records (obsoleteRecords)
- Mark these rows as UPDATE (markAsUpdate)
- Set value for SCD columns such as IsActive and ValidTo (scdColumnsObsolete)
- Drop the temporary column Hash (dropTempColumns2)
- Union the two streams (unionResults)
- Write the results into the Delta Lake (sinkCustomer)
- Create a pipeline that will incrementally load data as new files arrive.
- Pipeline (pipelineDimIncrementalLoad)
- Data flow (Source - rawCustomer)
- Data flow (Source - dimCustomer)
- Data flow (Filter - activeCustomers)
- Data flow (Derived column - addHashDim)
- Data flow (Aggregate - maxSurrogateKey)
- Data flow (Exists - existingRecords)
- Data flow (Exists - newRecords)
- Data flow (Derived column - addHash)
- Data flow (Exists - changedRecords)
- Data flow (Union - unionNewActive)
- Data flow (Alter row - markAsInsert)
- Data flow (Surrogate key - addTempKey)
- Data flow (Join - joinMaxSurrogateKey)
- Data flow (Derived column - scdColumns)
- Data flow (Select - dropTempColumns)
- Data flow (Exists - obsoleteRecords)
- Data flow (Alter row - markAsUpdate)
- Data flow (Derived column - scdColumnsObsolete)
- Data flow (Select - dropTempColumns2)
- Data flow (Union - unionResults)
- Data flow (Sink - sinkCustomer)
- Pipeline (pipelineDimIncrementalLoad)
- Debug Pipeline
In this module, we will be creating a pipeline to incrementally load the Customers dimension table. The transformation logic will be encapsulated within a data flow and will follow an SCD Type 2 pattern, this is where a new record is added to the dimension table to cater for data changes.
-
Navigate to the Integrate hub
-
Under Pipelines, click on the ellipsis [...] icon to the right of the
Customersfolder and select New pipeline -
Rename the pipeline to
C3 - pipelineDimIncrementalLoad -
Under Parameters, click New
-
Set the name of the parameter to
fileName -
Within Activities, search for
Data flow, and drag the Data flow activity onto the canvas -
Rename the activity
incrementalLoad -
Switch to the Settings tab
-
Next to the Data flow property, click New
In this step, we start with a source transformation that will reference a delimited text file (CSV) in the raw layer of our data lake. The data flow will include a file name parameter, this will allow the pipeline to dynamically pass a file name at runtime.
-
Enable Data flow debug
-
Rename the data flow
dataFlowDimIncrementalLoad -
Under Parameters, click New
-
Rename parameter1 to
fileName -
Within the data flow canvas, click Add Source and select Add source
-
Rename the Output stream name to
rawCustomer -
Set the Source type to Inline
-
Set the Inline dataset type to DelimitedText
-
Set the Linked Service to the Synapse Workspace Default Storage.
-
Switch to the Source options tab
-
Click the Browse icon
-
Navigate to
01-raw > wwi > customersand click OK -
Click inside the File name text input and click Add dynamic content
-
Under Expression elements click Parameters, select Filename, and click Save and finish
-
Enable First row as header
-
Switch to the Projection tab and click Import schema
-
Click Import
-
Under Data flow parameters, set the fileName property to an existing CSV file that resides within
01-raw > wwi > customersand click Save.- Tip #1: In a new window, open the Azure Portal, navigate to the storage account, and use the Storage Browser to find an existing file.
- Tip #2: To see the effect of new data during development, select the second CSV file (with the latest timestamp).
- Note: The string must be wrapped in single quotes.
-
Switch to the Data preview tab and click Refresh
In this step, we will add a second source transformation that will reference the existing Customer dimension table (Delta Lake) in the curated layer of our data lake.
-
Within the data flow canvas, click Add Source and select Add source
-
Rename the Output stream name to
dimCustomer -
Set the Source type to Inline
-
Set the Inline dataset type to Delta
-
Set the Linked Service to the Synapse Workspace Default Storage.
-
Switch to the Source options tab and click the Browse icon
-
Navigate to
03-curated > wwi > customersand click OK -
Set the Compression type to snappy
-
Switch to the Projection tab and click Import schema
-
Click Import
-
Switch to the Data preview tab and click Refresh
The Filter transformation allows row filtering based upon a condition. In this step, we will filter the Customers dimension table to only include rows that are active. This is a necessary step as we will eventually compare the new incoming data with the existing active data.
-
Click the [+] icon to the right of
dimCustomer, under Row modifier select Filter -
Rename the Output stream name to
activeCustomers -
Set the Filter on property to
IsActive == 1 -
Switch to the Data preview tab and click Refresh
The Derived Column transformation allows us to generate new columns and/or modify existing columns. In this step, we are adding a new column called Hash. This column is calculated by calling the md5 function against the same columns that exist in the source stream (i.e. excludes dimension columns such as CustomerSK, IsActive, ValidFrom, and ValidTo). The md5 function returns a 32-character hex string which can be used to calculate a fingerprint for a row. This will be used later in the module to compare against a hash from the new data stream.
-
Click the [+] icon to the right of
activeCustomers, under Schema modifier select Derived Column -
Rename the Output stream name to
addHashDim -
Copy and paste the Column values from the table below
Column Expression Hashmd5(CustomerID,CustomerAddress) -
Switch to the Data preview tab and click Refresh
The Aggregate transformation defines aggregations of columns in your data streams. In this step, we are going to use the Aggregate transformation to calculate the max CustomerSK value. This will be referenced by our data flow for INSERT operations so that the Customer surrogate key can resume incrementing from the last max value.
-
Click the [+] icon to the right of
activeCustomers, under Multiple inputs/outputs select New branch -
Click the [+] icon to the right of
activeCustomers(new branch), under Schema modifier select Aggregate -
Rename the Output stream name to
maxSurrogateKey -
Switch to Aggregates
-
Copy and paste the Column values from the table below
Column Expression MaxCustomerSKmax(CustomerSK) -
Switch to the Data preview tab and click Refresh
The Exists transformation is a row filtering transformation that checks whether your data exists in another source or stream. The output includes all rows in the left stream that exist or don't exist in the right stream. In this step, we are going to return all rows from the left stream (rawCustomer) where the CustomerID exists in the right stream (activeCustomers).
-
Click the [+] icon to the right of
rawCustomer, under Multiple inputs/outputs select Exists -
Rename the Output stream name to
existingRecords -
Set the Right stream to
activeCustomers -
Set the Exist type to Exists
-
Under Exists conditions, set the Left and Right to
CustomerID -
Switch to the Data preview tab and click Refresh
In this step, we will add a second exists transformation that will return records from the left stream (rawCustomer) that do not exist in right stream (activeCustomers) based on the CustomerID (new records).
-
Click the [+] icon to the right of
rawCustomer, under Multiple inputs/outputs select New branch -
Click the [+] icon to the right of
rawCustomer(new branch), under Multiple inputs/outputs select Exists -
Rename the Output stream name to
newRecords -
Set the Right stream to
activeCustomers -
Set the Exist type to Doesn't exist
-
Under Exists conditions, set the Left and Right to
CustomerID -
Switch to the Data preview tab and click Refresh
In this step, we are adding a new column called Hash to the existingRecords. This column is calculated by calling the md5 function against the columns. The md5 function returns a 32-character hex string which can be used to calculate a fingerprint for a row.
-
Click the [+] icon to the right of
existingRecords, under Schema modifier select Derived Column -
Rename the Output stream name to
addHash -
Copy and paste the Column values from the table below
Column Expression Hashmd5(columns()) -
Switch to the Data preview tab and click Refresh
In this step, we will add a third exists transformation that will return records from the left stream (addHash) that do not exist in right stream (addHashDim) based on the Hash field (changed records). This will identify existing customers where one or more customer attributes (e.g. CustomerAddress) has changed.
-
Click the [+] icon to the right of
addHash, under Multiple inputs/outputs select Exists -
Rename the Output stream name to
changedRecords -
Set the Right stream to
addHashDim -
Set the Exist type to Doesn't exist
-
Under Exists conditions, set the Left and Right to
Hash -
Switch to the Data preview tab and click Refresh
Union will combine rows from multiple data streams into one. In this step, we will combine data from the incoming stream changedRecords, with stream newRecords. This will reflect active records (either those customers who exist in the dimension table but have had changes and/or net new customers).
-
Click the [+] icon to the right of
changedRecords, under Multiple inputs/outputs select Union -
Rename the Output stream name to
unionNewActive -
Under Union with, set the Streams to
newRecords -
Switch to the Data preview tab and click Refresh
Alter Row set the INSERT, DELETE, UPDATE, and UPSERT policies on rows based on conditions. Each row will be marked with the policy corresponding to the first-matching expression. In this step, we will mark all rows from the incoming stream unionNewActive with the INSERT policy.
-
Click the [+] icon to the right of
unionNewActive, under Row modifier select Alter Row -
Rename the Output stream name to
markAsInsert -
Under Alter row conditions, set the condition to Insert If and the expression as
true() -
Switch to the Data preview tab and click Refresh
Surrogate Key adds an incrementing key value to each row of data. In this step, we will add a temporary surrogate key TempKey, that increments with a starting value of 1. Note: The eventual key value for each row will be offset in a subsequent transformation step by the MAX surrogate key value found in the existing dimension table.
-
Click the [+] icon to the right of
markAsInsert, under Schema modifier select Surrogate Key -
Rename the Output stream name to
addTempKey -
Set the Key column to
TempKey -
Switch to the Data preview tab and click Refresh
Join will combine data from two streams, the output will include all columns from both sources based on a join condition. In this step, we will combine all the columns from the left stream addTempKey, with all the columns from the right stream maxSurrogateKey.
-
Click the [+] icon to the right of
addTempKey, under Multiple inputs/outputs select Join -
Rename the Output stream name to
joinMaxSurrogateKey -
Set the Right stream to
maxSurrogateKey -
Set the Join type to
Custom (cross) -
Set the Condition to
true() -
Switch to the Data preview tab and click Refresh
In this step, we are adding columns CustomerSK, IsActive, ValidFrom, and ValidTo to the incoming stream joinMaxSurrogateKey.
CustomerSKis calculated by addingMaxCustomerSKtoTempKeyIsActiveis set to1ValidFromis set to the filename timestampValidTois set to9999-12-31 00:00:00
-
Click the [+] icon to the right of
joinMaxSurrogateKey, under Schema modifier select Derived Column -
Rename the Output stream name to
scdColumns -
Copy and paste the Column values from the table below
Column Expression CustomerSKTempKey + MaxCustomerSK -
Click Add then select Add column
-
Copy and paste the Column values from the table below
Column Expression IsActive1 -
Click Add then select Add column
-
Copy and paste the Column values from the table below
Column Expression ValidFromtoTimestamp(split($fileName,'.')[1], 'yyyyMMddHHmmssSSS') -
Click Add then select Add column
-
Copy and paste the Column values from the table below
Column Expression ValidTotoTimestamp('9999-12-31 00:00:00') -
Switch to the Data preview tab and click Refresh
Select can be used to rename, drop, and reorder columns. In this step, we will drop the temporary columns that no longer need to be propagated downstream - Hash, TempKey, and MaxCustomerSK. In addition, we will reorder the columns by moving CustomerSK to the first position.
-
Click the [+] icon to the right of
scdColumns, under Schema modifier select Select -
Rename the Output stream name to
dropTempColumns -
Under the Input columns, delete the
Hash,TempKey, andMaxCustomerSKcolumns -
On the left hand side of the
CustomerSK, click and drag the column to the first position -
Switch to the Data preview tab and click Refresh
In this step, we will add a fourth exists transformation that will return records from the left stream (addHashDim) that exist in right stream (changedRecords) based on the CustomerID field. This will identify the customer records that exist in the Delta Lake table but are now obsolete due to new changes, and therefore will need to be expired (e.g. IsActive = 0) which will be set in a subsequent transformation step.
-
Click the [+] icon to the right of
addHashDim, under Multiple inputs/outputs select Exists -
Rename the Output stream name to
obsoleteRecords -
Set the Right stream to
changedRecords -
Set the Exist type to Exists
-
Under Exists conditions, set the Left and Right to
CustomerID -
Switch to the Data preview tab and click Refresh
In this step, we will mark all rows from the incoming stream obsoleteRecords with the UPDATE policy.
-
Click the [+] icon to the right of
obsoleteRecords, under Row modifier select Alter Row -
Rename the Output stream name to
markAsUpdate -
Under Alter row conditions, set the condition to Update If and the expression as
true() -
Switch to the Data preview tab and click Refresh
In this step, we are updating columns IsActive and ValidTo from the incoming stream markAsUpdate.
IsActiveis set to0ValidTois set to the filename timestamp
-
Click the [+] icon to the right of
markAsUpdate, under Schema modifier select Derived Column -
Rename the Output stream name to
scdColumnsObsolete -
Copy and paste the Column values from the table below
Column Expression IsActive0 -
Click Add then select Add column
-
Copy and paste the Column values from the table below
Column Expression ValidTotoTimestamp(split($fileName,'.')[1], 'yyyyMMddHHmmssSSS') -
Switch to the Data preview tab and click Refresh
In this step, we will drop the temporary column Hash.
-
Click the [+] icon to the right of
scdColumnsObsolete, under Schema modifier select Select -
Rename the Output stream name to
dropTempColumns2 -
Under the Input columns, delete the
Hashcolumn -
Switch to the Data preview tab and click Refresh
In this step, we will combine data from the incoming stream dropTempColumns, with stream dropTempColumns2. This will reflect all rows that will be written to the sink using an INSERT or UPDATE operation.
-
Click the [+] icon to the right of
dropTempColumns, under Multiple inputs/outputs select Union -
Rename the Output stream name to
unionResults -
Under Union with, set the Streams to
dropTempColumns2 -
Switch to the Data preview tab and click Refresh
Sink writes the net result of our transformation into a destination data store. In this step, we will write the results from the incoming stream unionResults to the destination Delta Lake table.
-
Click the [+] icon to the right of
unionResults, under Destination select Sink -
Rename the Output stream name to
sinkCustomer -
Set the Sink type to Inline
-
Set the Inline dataset type to Delta
-
Set the Linked Service to the Synapse Workspace Default Storage
-
Switch to the Settings tab and click the Browse icon
-
Navigate to
03-curated > wwi > customersand click OK -
Set the Compression type to
snappy -
Set the Update method to Allow insert and Allow upsert
-
Set the Key columns to
CustomerSK -
Switch to the Data preview tab and click Refresh
Update the Data Flow activity within the pipeline to pass the pipeline parameter @pipeline().parameters.fileName to the Data Flow parameter fileName.
-
Navigate back to the pipeline
C3 - pipelineDimIncrementalLoad -
Click to focus on the Data flow activity and switch to the Parameters tab
-
Under Data flow parameters, click inside the fileName Value and select Pipeline expression
-
Copy and paste the code snippet and click OK
@pipeline().parameters.fileName
-
Click Publish all
-
Click Publish
To test that our pipeline is working correctly, we will trigger a manual run using the Debug capability.
-
Click Debug
-
Set the fileName parameter value to the name of the second CSV file (with the latest timestamp) and click OK
-
Once successful, navigate to the Data hub, browse the data lake folder structure to
03-curated > wwi, right-click the foldercustomers, and select New SQL Script > Select TOP 100 rows -
Set the File type to Delta format and click Apply
-
Click Run
Note: You will notice there are six records in total (five active, one inactive). Try to alter the SQL query so that you only see active records sorted by CustomerID.
You have successfully setup a pipeline to incrementally load the dimension table (Customer) following the SCD Type 2 pattern using the Delta Lake format.
Azure Synapse Analytics
- 1 x Pipeline (C3 - pipelineDimIncrementalLoad)
- 1 x Data flow (dataFlowDimIncrementalLoad)
Azure Data Lake Storage Gen2
- 1 x Delta log file (03-curated/wwi/customers/_delta_log)
- 7 x Parquet files (03-curated/wwi/customers)



























































































































































