SSIS Table Driven Package Configurations with Row Level Filtering

SSIS Table Driven Package Configurations with Row Level Filtering

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.

Why can’t we do this with standard package configurations?

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:

CREATE TABLE [dbo].[SSIS Configurations]
( ConfigurationFilter NVARCHAR(255) NOT NULL,
ConfiguredValue NVARCHAR(255) NULL,
PackagePath NVARCHAR(255) NOT NULL,
ConfiguredValueType NVARCHAR(20) NOT NULL)

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.
What we’d like to do is capture in the provided screen snapshot:














<---- Here's what we tried!












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.

The Custom SSIS Solution

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: dbo.ssis_custom_configurations. The SSIS tasks must be placed at the beginning of each package, so we placed them in the OnPreExecute Event Handler area.
In the sections that follow we will dissect each of these components in details so you can fully understand how to implement this solution.


1. Package Variables

There are several variables that are required to drive the custom solution. These are in the table below:

str_customer_name
This package variable provides the customer name we wish to processs and is actually
used to dynamically construct the ConnectString that points to the customer's Staging
Database. For example -- if we have a customer of 'ToscanosHardware' our staging
database will be ToscanosHardware_Stage.

str_configured_object_name
What is the name of the object are we going to focus on? We've pointed to both Connections
here and package variables. For example -- we have a generic Connection String we called
stage.oledb. Using our solution, this default catalog / database is changed leveraging the
str_customer_name.

str_configured_value
This package variable holds the new connection string value or packag variable value that
is obtained from the custom table.

str_config_filter
This package variable actually holds the value we are using as our row level filter. It is an
expression that combines the package name along with the customer name. Here's the
expression: @[System::PackageName]+"_"+ @[User::str_customer_cd] A sample
value could be 'extract_customer_data_ToscanosHardware'

rs_config
Hold the full result set (the rows returned from the package configuration table that whose
filter_name matches the str_config_filter package variable.


2. Required SSIS Tasks


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:























2.1 The GET CONFIG VALUES Execute SQL Task

The EXEC SQL Statement selects all rows from the custom package configuration table
using the str_config_filter in the where clause. Let’s assume we are currently working in a
package that extracts sales details data for the ‘ToscanosHardware’ customer. In this case,
our SSIS package name is ‘ext_sales_details’ so our str_config_filter is
‘ext_sales_details_ToscanosHardware’ The actual select statement used by the Execute
SQL Task is below followed by a screen snapshot of the actual task:

SELECT
configured_object_name,
property_name,
configured_value
FROM
ssis_configurations
WHERE
filter_name = ?


The select statement maps the User::str_config_filter package variable to the parameter.
Also, the User::rs_config package variable holds the full result set allowing a For Each SSIS
container to be used.




































2.2 The For Each Container

The For Each Container uses the output of the Execute SQL Task which is a result set from
the custom package configuration table. The Collection Tab specifies the Users::rs_config
object source variable as seen below:





Finally, the columns returned are mapped to the following package variables as specified in
the Variable Mappings tab:




























Finally, the columns returned are mapped to the following package variables as specified in
the Variable Mappings tab:



2.3 SCR - SETUP CONFIGS Script Task

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.

Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Runtime

_
_
Partial Public Class ScriptMain
Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase

Enum ScriptResults
Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success
Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure
End Enum
Public Sub Main()
Try
Select Case Dts.Variables("str_configured_object_name").Value.ToString
Case "Stage.OLEDB"
If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then
Dts.Connections("Stage.OLEDB").ConnectionString =
Dts.Variables("str_configured_value").Value.ToString
End If
Case "Stage.ADONET"
If Dts.Variables("str_property_name").Value.ToString = "ConnectionString" Then
Dts.Connections("Stage.ADONET").ConnectionString =
Dts.Variables("str_configured_value").Value.ToString
End If
Case "str_product_input_filename_pattern"
If Dts.Variables("str_property_name").Value.ToString = "Value" Then
Dts.Variables("str_product_input_filename_pattern").Value =
Dts.Variables("str_configured_value").Value.ToString
End If
Case "str_input_feed_directory"
If Dts.Variables("str_property_name").Value.ToString = "Value" Then
Dts.Variables("str_input_feed_directory").Value =
Dts.Variables("str_configured_value").Value.ToString
End If
End Select

Dts.TaskResult = ScriptResults.Success
Catch ex As Exception
Debug.Print(ex.Message)
Dts.TaskResult = ScriptResults.Failure
End Try
End SubEnd Class

Conclusion


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.
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.

Errors locating SSIS XML package configuration files.

SSIS provides several ways to make a package configurable, including using database configurations, XML file configurations, and environment variables. Of the different methods, XML files are probably the simplest and most dynamic approaches. However, it can be frustrating to figure out why a package generates errors that “The configuration file cannot be found” or that it “Failed to load at least one of the configuration entries for the package.” Why can’t it locate the configuration file? The key is to understand how SSIS sets what I will call the ‘working folder’ (that’s my term, it’s not in SSIS anywhere).

Before discussing that, let me clarify the situation a bit. When you create an XML configuration file, if you specify the path to the file, then that path will be required on all development machines as well as the production machines. On a recent project, the client didn’t want to have a fixed path for the SSIS files, instead they wanted the packages to accept configuration from wherever the package files were located. So, by design we did NOT specify a folder location for the configuration files. Instead, we simply specified the file name so that the configuration file would ‘live’ in the same folder as package. This worked fine, however it revealed an unexpected behavior of SSIS – this notion of a ‘working folder’.

Question: What determines where SSIS will look for its files? Well, that depends on how you opened your project. Some people launch BIDS from the Start menu and then select the project from the ‘Recent Projects’ list or choose ‘File – Open -- Project/Solution’. If you use either of those methods, then the ‘working directory’ will be wherever the BIDS executables reside, most likely something like ‘C:\Program Files\Microsoft Visual Studio 8\Common7\IDE’. I’m guessing that this is NOT where you put your configuration files, so as a result, when you open a package, you get an error message that the configuration files can’t be found. There’s really a simple solution to this and it is to 1) locate your configuration files (dtsconfig files) in the same directory as your solution file (.sln file), and then to 2) ALWAYS open your solution by double-clicking the solution file (.sln file). This will set the ‘working folder’ to be where the solution lives, your configuration file will be read correctly, and the errors about not finding the configuration should be gone.

Now, that works fine when you are developing, because you are specifying where the files open from, but what about production? How do you specify the ‘working folder’ when scheduling the packages using SQL Agent? Well, we ran into that situation as well, and sure enough when SQL Agent tries to execute a package, its ‘working folder’ defaults to the location of the DTEXEC executable. So, a simple workaround was to create a batch file that first changes to the directory where the packages and configuration files live, and then execute DTEXEC with the command line options that we wanted. Then, in SQL Agent, instead of using the ‘SQL Server Integration Services package’ type job, use an ‘Operating System (CmdExec)’ type job and just call the batch file. Worked like a charm. If the location of the packages ever needs to change to a different folder, drive, or even server, it’s a simple change to the batch file to reference that new location.

In closing, having a fixed configuration location or using an environment variable to hard-code the location of configuration files would avoid this situation, but places requirements on server configuration and directory structure. SSIS can support completely dynamic configuration file location, but you need to be aware of how it sets its ‘working folder’.

Creating a SharePoint 2010 Business Intelligence VM Image (using SQL Server 2008 R2 CTP)

Introduction

SharePoint is becoming more and more prominent as the delivery mechanism for BI solutions within the Microsoft stack. The SharePoint 2010 BETA along with SQL Server 2008 R2 further strengthen the overall business intelligence capabilities and functionality possible in an organization.

I have a VM image to ramp up on SharePoint 2010 itself but in order to expand into all of the new BI features I wanted to create a new one (from scratch) with the latest SQL Server 2008 R2 CTP. So I did! It was a very tedious process but I found a guide to assist me.

I used the wonderful instructions laid out here: http://www.sharepointdevwiki.com/display/spadmin2010/Installing+SharePoint+2010+Public+Beta

However, since I was using SQL Server 2008 R2 and wanted to configure it for full business intelligence usage, I needed to modify the steps slightly. This post will outline those steps and show any updated walkthroughs.

These instructions/steps are needed only when using SQL Server 2008 R2 CTP as there are several installation issues when integrating with SharePoint 2010. Hopefully in the release these will be corrected.


Installation Steps

1) Follow Steps 00, 0b, 0c and 01 from the SharePoint Dev Wiki guide

2) Instead of step 02, we will install SQL Server 2008 R2 CTP but that comes later! DO NOT INSTALL SQL Server 2008 yet.

3) Steps 3-9 can now be skipped as everything there will be (or has been) installed with Windows Server 2008 R2, SQL 2008 R2, and SharePoint Pre-Reqs.

4) Do not even look at Step 10 - skip to 10b and 10c. I happened to disregard the notes about using the Administrator account for everything and ran into an issue at the end. You may want to look at Step 15 and review the supporting links (as well as the supporting links within those pages). Key thing is to not setup that sp_admin account for this VM.

Also, I decided after the fourth time to actually install the hotfix first (10c), reboot, then install the SharePoint Pre-Reqs (10b), and reboot again. Take the time now because if something fails you could waste hours or days going through the same steps again and again.

5) Perform Step 11 - DO NOT RUN THE CONFIGURATION WIZARD - UNCHECK THE CHECKBOX. Click on Close. The next step here will perform the rest of the configuration.

6) Install SQL Server Analysis Services Integration Mode - (see walkthrough below).

7) Perform Steps 13 and 14
It does take a few minutes to start the User Profile service and to run the synchronization. I did not see anything in the Running Jobs (the first time but the second time I did).


8) Perform Step 15 - before you click on the User Profile Service Application, select it first by click to the right of the link. Then on the top ribbon, click on Administrators (see screens below). The Administrator account should be in there automatically but only the "Retrieve People Data..." permission is selected. I selected Full Control as the TechNet links from those supporting links discussed about the account having full control.




I thought the Profile load was finished and found 0 users but it just took some time to complete. The status said it was done but apparently something was running in the background.

9) Now go back to the SQL Server 2008 R2 installation and install the default instance with Reporting Services (Integrated) and Analysis Services (native). See walkthrough below. 


10) Configure Reporting Services - Integrated Mode.  See walkthrough below.

11) Optional: Install Visual Studio 2010

12) Optional: Install Office 2010 BETA. Include the Visual Studio Tools for Office (VSTO).





SQL Server 2008 R2 - Analysis Services Integrated Mode Installation and Configuration Walkthrough


























Click the "Use the same account..." button and enter the Administrator credentials. Click OK.



Click on "Add Current User". I was paranoid the "umpteenth" time and actually added the Local Service, Local System, and Network Service accounts in attempts to prevent the time-out issue (the issue is described below).








VERY IMPORTANT!
Since this is a domain controller, a time out issue will occur as explained here: http://powerpivotgeek.com/2009/11/17/installing-powerpivot-for-sharepoint-on-a-domain-controller/
You need to monitor the services in Server Manager - Services  (while the installation is running) and change the SQL Server Analysis Services (GeminiBI) Service back to the administrator account and make sure it is started. This needs to be corrected as soon as it happens.

You do have time however. The service won't even be listed until it gets installed. The switch occurs about midway through the ASSPIInstallFarmAction. When the install is up to this point, you can see the service listed. I just kept hitting the Refresh and I did see it change eventually. Don't forget to Start the service after you change the Log On back to the Administrator account.





Click Install!



If this step does not complete successfully, you might as well delete the VM and start over. It took me three days to get this right. Possible errors are: 1) timeout, 2) Object Not Set to Instance of an Object, and 3) Could not load or find assembly Microsoft.AnaysisServices.SharePoint.Integrated. There could be others but I wouldn't even bother trying to uninstall and re-install - I tried too many times only to find the best way was to just start over from scratch. Believe me, it will save you hours.


After completion. Go to Central Admin and click on the Configuration Wizards:

Select the Farm Configuration.

Click Next




Use the Existing Managed Account and make sure the Administrator is selected. Click Next.


This process already created a root site collection (I was a little upset about that). So we can skip this part. Click Skip.



Click Finish!






Default Instance - SQL Server 2008 R2 Installation Walkthrough (after Gemini Instance Install)
(For Step 9 above)












Select All. Click Next.

































SQL Server 2008 R2 - Reporting Services Configuration (Integrated Mode) Walkthrough
(For Step 10 above)







If you selected Integrated mode during installation, many of these settings are already in place. Go through each screen and make sure there is no warning symbol. Click Apply on the screens that show settings that haven't been set. The walkthrough may go through some additional details that aren't needed for your case. These mimic the configuration if a mode (native or integrated) was not selected.


 





If the database is not set, click on Change Database.

 











Click Exit.


Download and run the Reporting Services Add-In for SharePoint 2010:
http://www.microsoft.com/downloads/details.aspx?FamilyID=16bb10f9-3acc-4551-bacc-bdd266da1d45&displaylang=en












Click Finish.

Go to Central Admin, and look under General Application Settings:



Click on Reporting Services Integration.




Click Close.