<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>RDA Corp - Business Intelligence and SQL Server</title>
<link>http://www.beyeblogs.com/rda_corp/</link>
<description></description>
<language>en</language>
<copyright>Copyright 2010</copyright>
<lastBuildDate>Mon, 22 Feb 2010 20:26:00 -0700</lastBuildDate>
<generator>http://www.movabletype.org/?v=3.33</generator>
<docs>http://blogs.law.harvard.edu/tech/rss</docs> 


<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_1.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_1.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_2.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_2.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_3.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_3.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_4.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_4.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_5.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_5.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_6.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_6.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_7.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_7.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_8.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_8.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_9.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_9.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_10.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_10.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_11.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_11.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_12.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_12.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_13.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_13.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>

<item>
<title>SSIS Table Driven Package Configurations with Row Level Filtering</title>
<description><![CDATA[<strong>SSIS Table Driven Package Configurations with Row Level Filtering</strong><br /><br />Recently we faced a challenge in which we wanted to implement SSIS table-driven package configurations with a twist. We wanted to have a common or shared SSIS package configuration table and have the packages that make up our solution dynamically filter or utilize only specific package configuration rows from this table based on a package variable value. For example â€ letâ€™s assume our package variable is the customer name with a sample value of: â€˜ToscanosHardware.â€™ What we like to do is to have our SSIS packages look in the User::str_customer_name package variable for the customer-to-process, and then only utilize package configuration rows that apply to this specific customer. (there is a configuration filter column in the SSIS package configuration table) In other words, weâ€™d like to implement table driven package configurations with row level filtering based on a package variable value.<br /><br /><strong>Why canâ€™t we do this with standard package configurations?</strong><br /><br />Given the current way in which table based package configurations work, we couldnâ€™t find a way to implement row level filtering based on a package variable. Letâ€™s assume we setup standard table based package configuration that use the following table:<br /><br /><span style="color:#666666;">CREATE TABLE [dbo].[SSIS Configurations]<br />( ConfigurationFilter NVARCHAR(255) NOT NULL,<br />ConfiguredValue NVARCHAR(255) NULL,<br />PackagePath NVARCHAR(255) NOT NULL,<br />ConfiguredValueType NVARCHAR(20) NOT NULL)<br /></span><br />When, you create a package configuration entry in this table, you are asked to provide a ConfigurationFilter value. Hereâ€™s where weâ€™d like very much to use an SSIS Expression and tell SSIS to filter based on what that expression evaluation to! Wouldnâ€™t it be great to be able to provide a filter value that uses a package variable as part of an expression? This does not seem to work because what filter value we provide is actually literally interpreted.<br />What weâ€™d like to do is capture in the provided screen snapshot:<br /><br /><br /><br /><a href="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s1600-h/Package Configuration wizard.png"><img id="BLOGGER_PHOTO_ID_5441244466726237762" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 340px" alt="" src="http://3.bp.blogspot.com/_k60MffeGnb4/S4MvA3dG9kI/AAAAAAAAAEs/QpO_yqmjS-I/s400/Package Configuration wizard.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong><span style="color:#ff0000;"><---- Here's what we tried!</span></strong><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />Notice for the Configuration filter value we provide. We attempt to provide a SSIS expression here. However, the value we provide: User::customer_name   '_Stage_Connection' is not evaluated but is instead literally interpreted.<br /><br /><strong>The Custom SSIS Solution</strong><br /><strong></strong><br />We ended up creating our own custom SSIS table-driven solution that was both straight-forward and easy to implmenent. Our custom SSIS solution requires several package variables along with SSIS tasks that reference a custom package configuration table that has the same column layout as the standard package configurations, but we appropriately named our table: <strong>dbo.ssis_custom_configurations.</strong> The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.<br />In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.<br /><br /><br /><strong>1. Package Variables</strong><br /><br />There are several variables that are required to drive the custom solution. These are in the table below:<br /><br /><strong>str_customer_name</strong><br />This package variable provides the customer name we wish to processs and is actually<br />used to dynamically construct the ConnectString that points to the customer's Staging<br />Database. For example -- if we have a customer of 'ToscanosHardware' our staging<br />database will be ToscanosHardware_Stage.<br /><br /><strong>str_configured_object_name</strong><br />What is the name of the object are we going to focus on? We've pointed to both Connections<br />here and package variables. For example -- we have a generic Connection String we called<br /><em>stage.oledb. </em>Using our solution, this default catalog / database is changed leveraging the<br />str_customer_name.<br /><br /><strong>str_configured_value</strong><br />This package variable holds the new connection string value or packag variable value that<br />is obtained from the custom table.<br /><br /><strong>str_config_filter</strong><br />This package variable actually holds the value we are using as our row level filter. It is an<br />expression that combines the package name along with the customer name. Here's the<br /><span style="color:#666666;"><span style="color:#000000;">expression: </span><em>@[System::PackageName] "_"  @[User::str_customer_cd]</em></span> A sample<br />value could be '<span style="color:#000000;">extract_customer_data_ToscanosHardware'</span><br /><br /><strong>rs_config</strong><br />Hold the full result set (the rows returned from the package configuration table that whose<br />filter_name matches the str_config_filter package variable.<br /><br /><br /><strong>2. Required SSIS Tasks</strong><br /><br /><br />The SSIS tasks below must be copied to the beginning of each package that you wish to participate in the custom package configurations solution. The tasks are below:<br /><br /><br /><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s1600-h/Required SSIS Tasks.png"><img id="BLOGGER_PHOTO_ID_5441254868748524818" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 196px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M4eWAe3RI/AAAAAAAAAE8/4rZ8dDMmJcw/s400/Required SSIS Tasks.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><strong>2.1 The GET CONFIG VALUES Execute SQL Task</strong><br /><br />The EXEC SQL Statement selects all rows from the custom package configuration table<br />using the str_config_filter in the where clause. Letâ€™s assume we are currently working in a<br />package that extracts sales details data for the â€˜ToscanosHardwareâ€™ customer. In this case,<br />our SSIS package name is â€˜ext_sales_detailsâ€™ so our str_config_filter is<br />â€˜ext_sales_details_ToscanosHardwareâ€™ The actual select statement used by the Execute<br />SQL Task is below followed by a screen snapshot of the actual task:<br /><br /><span style="color:#666666;">SELECT<br />configured_object_name,<br />property_name,<br />configured_value<br />FROM<br />ssis_configurations<br />WHERE<br />filter_name = ?</span><br /><br />The select statement maps the User::str_config_filter package variable to the parameter.<br />Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS<br />container to be used.<br /><br /><br /><br /><a href="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s1600-h/EXEC SQL GET CONFIG VALUES.png"><img id="BLOGGER_PHOTO_ID_5441257048661447842" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 329px" alt="" src="http://4.bp.blogspot.com/_k60MffeGnb4/S4M6dO0OVKI/AAAAAAAAAFE/pEYMEVDGOfI/s400/EXEC SQL GET CONFIG VALUES.png" border="0" /></a><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><p></p><p><br /></p><br /><br /><br /><br /><br /><strong></strong><br /><strong>2.2 The For Each Container</strong><br /><br />The For Each Container uses the output of the Execute SQL Task which is a result set from<br />the custom package configuration table. The Collection Tab specifies the Users::rs_config<br />object source variable as seen below:<br /><br /><br /><br /><br /><br />Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:<br /><br /><p></p><p><br /></p><br /><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s1600-h/For Each Container.png"><img id="BLOGGER_PHOTO_ID_5441258629279715154" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M75PE_D1I/AAAAAAAAAFU/4Q20rktrr6o/s400/For Each Container.png" border="0" /></a><br /><br /><br /><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><br /><br /><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><p> </p><p> </p><p> </p><p> </p><p>Finally, the columns returned are mapped to the following package variables as specified in<br />the Variable Mappings tab:</p><p></p><p></p><p></p><p></p><p></p><p> </p><p> </p><br /><br /><p><a href="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s1600-h/For Each Loop Editor.png"><img id="BLOGGER_PHOTO_ID_5441259605216970514" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; WIDTH: 400px; CURSOR: hand; HEIGHT: 382px" alt="" src="http://1.bp.blogspot.com/_k60MffeGnb4/S4M8yCujxxI/AAAAAAAAAFc/EBvPQ9gZ62E/s400/For Each Loop Editor.png" border="0" /></a></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong></p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong></strong> </p><p><strong>2.3 SCR - SETUP CONFIGS Script Task</strong><br /><br />The Script Task uses the package variables set in the For Each loop and actually changes the values of either the Connection String or the Package Variable Values. It is up to you to add the rows between the Select Case and the End Select. In the example below, these rows reference the connection strings and/or package variables you wish to change via this custom solution. In the example script below we are changing the ConnectionString values for both the Stage.OLEDB connection and the Stage.ADONET connection. Also, we are changing the values of the str_product_input_filename_pattern and the str_input_feed_directory package variables. These connection string rows and package variable rows must exist in the package configuration table. </p><p><span style="color:#000099;">Imports System<br />Imports System.Data<br />Imports System.Math<br />Imports Microsoft.SqlServer.Dts.Runtime<br /><br /><system.addin.addin("scriptmain",>_<br /><system.clscompliantattribute(false)>_<br />Partial Public Class ScriptMain<br />Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase<br /><br />Enum ScriptResults<br />Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success<br />Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure<br />End Enum<br />Public Sub Main()<br />Try<br />Select Case Dts.Variables("str_configured_object_name").Value.ToString<br />Case "Stage.OLEDB"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.OLEDB").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "Stage.ADONET"<br />If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then<br />Dts.Connections("Stage.ADONET").ConnectionString =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_product_input_filename_pattern"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_product_input_filename_pattern").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />Case "str_input_feed_directory"<br />If Dts.Variables("str_property_name").Value.ToString = "Value" Then<br />Dts.Variables("str_input_feed_directory").Value =<br />Dts.Variables("str_configured_value").Value.ToString<br />End If<br />End Select<br /><br />Dts.TaskResult = ScriptResults.Success<br />Catch ex As Exception<br />Debug.Print(ex.Message)<br />Dts.TaskResult = ScriptResults.Failure<br />End Try<br />End SubEnd Class</span></p><p><strong>Conclusion</strong></p><p><br />The custom SSIS solution worked like charm. We were able to actually pass the customer name as a parameter to the startup (master) package via a SQL Server Job. The master package that executed the children packages passed this customer name to the children via a Parent / Child package configuration. By doing this, we could have a generic SSIS solution that dynamically processed different customer data simply by having one job per customer.<br />We also embedded the required SSIS tasks in the OnPreExecute and OnPostExecute Event Handler events. This way we didnâ€™t have to clutter up each package. </p><p></p><p></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35862303-2587409262730056747?l=bisqlserver.blogspot.com' alt='' /></div><p>]]></description>
<link>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_14.php</link>
<guid>http://www.beyeblogs.com/rda_corp/archive/2010/02/ssis_table_driv_14.php</guid>
<category></category>
<pubDate>Mon, 22 Feb 2010 20:26:00 -0700</pubDate>
</item>


</channel>
</rss>