Professional Documents
Culture Documents
Pgina 1 de 69
MSDN Home > MSDN Library > Enterprise Development > Windows Server System > Microsoft SQL Server >
Microsoft SQL Server 2000 >
Page Options
Average rating:
9 out of 9
Rate this page
Print this page
E-mail this page
Add to Favorites
Summary: Discover the best practices for using DTS within the Data Warehousing Framework to capture and
present data as Business Intelligence solutions. (108 pages)
Contents
Introduction
DTS and the Data Warehousing Framework
Package Design Practices
Guidelines for Inclusion of Metadata in Package Designs
Analysis Services Management Practices
Decision Support Objects within DTS
Creating Partitions
Cloning Partitions
Merging Partitions
Dropping Partitions
Guidelines for Managing OLAP Partitions
Analysis Services Processing Task
Execute on Main Thread
Using DTSRUN to Perform Analysis Services Processing
Programming the Analysis Services Processing Task
Guidelines for Performing Analysis Services Processing with DTS
Practice Summary
Auditing and Error Handling Practices
Fail Package on First Error
Practice Summary
Enhancing DTS Functionality Practices
Conclusion
Appendix A About the Authors
Appendix B Code Listing for .NET Custom Task
Introduction
Business Intelligence (BI) solutions such as Data Marts and Data Warehouses rely heavily on tools to migrate
data between heterogeneous data sources and support consolidated analytical decision-making. Microsoft SQL
Server 2000 Data Transformation Services (DTS) provides the flexibility and advanced functionality to automate
the architecture by which operational data is captured and delivered to the end-users of BI applications. The
flexibility found within the DTS platform provides for a multitude of approaches to solving the data warehousing
requirements of a solution leveraging the Microsoft Data Warehousing Framework.
This white paper explores the best practices that can be leveraged in delivering comprehensive BI solutions via
the Microsoft Data Warehousing Framework. The white paper is comprised of six sections: Overview of the Data
Warehousing Framework; Package Design Practices; Extract, Transformation, and Loading (ETL) Practices;
Analysis Services Management Practices; and Enhancing DTS Functionality Practices. Each best practice section
defines the preferred approaches, the guidelines, and the benefits of the use of this practice.
This white paper begins with insight into the Data Warehousing Framework and DTS role within the Data
Warehousing Framework. The next section details the best practices for approaching DTS package design,
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 2 de 69
exploring concepts like metadata-driven configuration and modular package development. The white paper
details the best practices of extracting and staging source data, transforming and cleansing data in readiness for
the production data warehouse, and managing the loading of slowly changing dimensions and fact areas. The
practices for performing integrated management of the SQL Server 2000 Analysis Services are then covered
with approaches for managing the creation of and processing of OLAP partitions, along with other OLAP Cubes
and Dimensions. In the remaining sections, the best practices for monitoring the overall execution, through
error handling and auditing, of the DTS package solution architecture and enhancing this architecture through
custom programming are explored.
Technologists, familiar with the Data Transformation Services platform within SQL Server 2000, are the primary
audience for this white paper. For an overview of the features found within Data Transformation Services, read
the Data Transformation Services (DTS) in SQL Server 2000 white paper or consult the Microsoft SQL Server
Books Online.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 3 de 69
Metadata-Driven Approach
Driving Packages with the Dynamic Properties Task
The Dynamic Properties task, added in SQL Server 2000, is one of the most efficient ways to utilize package
configuration information (or metadata) stored outside of the DTS package. This information is read at runtime
and the execution is dynamically customized by this task. The task allows property information to be obtained
from sources such as INI files, relational DBMS queries and textual data files. Storing the package, or more
appropriately, the task, information within an external information source allows for packages to migrate nicely
between development and production environments and isolates the changes to the package configuration to
text files or DBMS tables. This also paves the way for modular package designs leveraging metadata.
Populating Global Variables via Execute SQL Task
Another method for sourcing package metadata information is to use the Execute SQL task and the output
rowset parameter to capture all of the settings for the global variables in a single query in lieu of multiple
queries with the Dynamic Properties task.
Use of the Execute SQL task requires that a minimal amount of ActiveX scripting be done to turn the multiple
rows of global variable records returned as a rowset into actual global variables. The example below shows the
necessary script to turn a three-column rowset (GlobalName, GlobalValue, and GlobalConversion), stored
in the global variable GlobalVariablesRowset, into a collection of global variables for the package.
Dim GlobalRowset, GlobalName, GlobalConversion
Set GlobalRowset = DTSGlobalVariables("GlobalVariablesRowset").Value
'Check for GlobalVariable Records within the GlobalRowset
If GlobalRowset.RecordCount <= 0 Then
'Exit the function and report failure
Main = DTSTaskExecResult_Failure
Exit Function
Else
GlobalRowset.MoveFirst()
Do While Not GlobalRowset.EOF
GloballName = GlobalRowset("GlobalName").value
GlobalConversion = GlobalRowset("GlobalConversion").value
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 4 de 69
strategy to benefits for doing so. The benefits can address the ease of maintenance, the support for remote
configuration of the package, or countless others.
z For text file based metadata (i.e., INI files or XML files), be certain to reference these files by fully qualified
UNCs (i.e., \\MyServer\MyShare\MyINIFile.INI) to make certain of the greatest portability within the
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 5 de 69
network environment.
z Consider using SQL Server relational tables for global variable information as this approach ensures the
overall connectivity to the source or target database and protects against issues like resource locking that
can be experienced with file-based resources.
z Drive settings that are apt to change such as server names, OLAP cubes and source file load paths from
metadata.
z Do not attempt to drive everything from metadata. By overusing metadata, not only will the metadata be
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 6 de 69
environment)
z Modularize the design of packages (i.e. ETL packages for Dimension Extract, Dimension Load, Fact Extract,
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 7 de 69
z Manage the execution of multiple packages with dependencies upon each other
z Desire to share variables between packages
z Encapsulate specific functionality, driven by metadata, which makes the child package re-usable.
Pursuing more than one of the above design goals is very common for moderate to complex ETL designs within
BI solutions.
Guidelines for Parent/Child Packages
While the tools to create parent/child package architectures offer a simple implementation, there are additional
guidelines to be considered when exploiting this practice. The most notable guidelines are:
z Manage the level of nesting among packages and try not to go more than two children deep.
z Understand the role of the two Failure properties of packages and tasks, respectively "Fail Package on First
SQL Server. Doing so eliminates the risk of exclusive file locks (when the package is stored as a structured
storage file) being placed upon the child package, thus destroying concurrency.
z Employ a naming convention that indicates the core function of the package (that is, dimension loading
packages begin with "DIM"; fact loading packages begin with "FACT", and so forth).
Practice Summary
Benefits
Incorporating metadata into the DTS architecture and relying upon multiple parent/child packages provides a
strong foundation for the BI solution. The most noteworthy of these are:
z Repeatable deployment
Using metadata to configure a package means that deployment is as easy as updating the metadata. This is
a sound approach when combined with the need to preserve the version (or GUID) of a child package called
from an Execute Package task.
z Parallelism made easy
Adopting a hierarchical mindset early in the overall design unveils the option of significant degrees of
parallelism through multiple threads calling the same package.
z Maintainability supporting rapid change
Designing one child package for a particular purpose provides the ability to "upgrade" an element of the
enterprise DTS architecture without touching several packages. The net result is a more rapid approach to
maintaining packages.
Precautions
The precaution areas for this practice and the subordinate approaches are limited but do exist. The key
precaution area is:
Longer initial design
The result of following the prescribed approaches is a longer period to design a package initially because of the
dependence on metadata and determining how metadata should be used. However, this doesn't mean that a
minor delay does not have its benefits. For the quick prototyping or one-off loading of data, the use of
parent/child packages or metadata might be more significant than the process DTS is being used to solve.
The means in which child packages are developed will create either a very manageable or barely manageable
architecture depending upon the thought put into the design and the desire to achieve the previously mentioned
goals. Following the guidelines and techniques provided, should help achieve a successful implementation of
Parent Child packages, building on the metadata driven design. Ultimately, beyond these design "best practice"
activities, the solution set to achieving the overall BI solution architecture with DTS is found in the next
sections.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 8 de 69
A UDL file is an object outside of DTS. As its name implies the file (*.UDL) provides access to data on any
of the system installed OLEDB providers. The UDL file maintains all of the connection information within the
file. DTS readily supports the UDL file as a data source for a package connection.
z Text file destination
DTS' support for text file destinations provides a convenient standard format for data from source systems
to be extracted into a file. Exporting to a file from a source system extract makes the remaining portions of
the ETL process easier to manage.
z Bulk Insert task
The Bulk Insert task is a functional means of loading data from a text file directly into the associated SQL
Server staging table. The benefits of bulk insertion include speed of loading as one of the overriding factors
for its use.
Figure 6. Connection and Datalink properties windows (click image to see larger version)
UDL files solve the portability of connection information among a solution's server resources. The graphic below
shows both a UDL file being configured and referenced from within DTS.
Selecting the Always read properties from UDL file option will ensure a connection based upon a UDL will
reference the connection information found within the UDL file at every execution. This functionality makes the
UDL file the "missing link" for metadata based connection information.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL S... Pgina 9 de 69
By taking data in the form of a text file, source systems can migrate between relational database platforms or
even more realistically just change schemas altogether and the BI solution will be blissfully unaware of any such
event. By insuring continued conformance to a text file layout, the burden resides with the updated source
system and the extraction package to pull the data into this format. The remainder of the ETL architecture
remains unchanged. Using mocked up copies of the text files, allows for the prototyping of data sources before
their extraction is complete making possible a more productive development lifecycle.
Access or use an instance of SQL Server and then move to another SQL Server. If the extracts still work by
only changing the UDL files, then the design is a success.
z Avoid trying to transform data when extracting or loading the staging environment. This puts an
unnecessary burden on the source system, extends the duration of the extract, and jeopardizes the validity
of the logic if the source system changes.
z Use the stage as the BI sandbox. Anything goes in this environment especially non-log intensive operations
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 10 de 69
LastName
Smith
FirstName
John
MiddleName
Edward
PersonChecksum
-52588501
PersonBinaryChecksum
-1292791390
An index can be placed on either or both the PersonChecksum and PersonBinaryChecksum columns to create a
Hash Index. Doing so would thus make the data results for the computed columns physical (or materialized)
within the table. Once the index is in place there is no need to reference the textual information about the
Person when performing a dimensional update, discussed a little later in this Best Practice section.
Computed columns can also support come of the common transformation types which typically occur in the
preparation of data for the final BI relational data store.
Types of Transformation
There are a limitless number of transformation types that can exist for data taken from source systems which
provide dimension and fact records. Some of the more common transformation types include:
z String parsing taking a subset of the string information found within a char or varchar datatype
z Type conversion taking the value found within a source column and representing it as a differing data
type in the final BI solution (i.e., tinyint value of 1 or 0 converted to a char(1) value of Y or N)
z Domain lookup transformation where the value from the source system is used to lookup an alternate
value from a data store (i.e., using the natural key for a dimension to lookup the surrogate key for the
dimension in the data mart)
z Numeric conversion conversion of a number to meet a standardized value across the entire data mart
(i.e., multi-national monetary sales are converted into US dollars for analysis)
z Domain data validation (bounds checking) transformation where values are checked to see if they
are within an acceptable bounds (i.e., sales dollars should be between $20,000 and -$20,000)
An equal number of limitless places exist within the ETL for transforming data. The general categories for these
transformation locations are:
z Outbound transformation transformation of data as it is extracted from the source system
z Inbound transformation transformation of data as it is loaded into the staging area
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 11 de 69
z Staging transformation transformation which occurs in the staging area after the data has been loaded
the staging area and inserted into the Dimension and Fact tables in the production data store
2.
Support for complex transformation implementations by making multiple passes through the data
3.
4.
2.
3.
2.
3.
The biggest cautions about this final approach are to not expect the same degree of performance as is offered
by Transact SQL and Stock DTS transformations. The overhead of using ActiveX Scripting logic typically
produces results that are remarkably slower than performing transformations using the other technical
approaches.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 12 de 69
the same order. A different checksum value will result if column order or parameter order is changed.
z If using ActiveX Scripting transformations, use the ordinal number of the column in lieu of its name for
better performance.
z Consider chunking as an option even if initial data sizes are small. Chunking provides the easiest means for
optimum performance.
Achieving efficient and effective results transforming the data within the Staging Area provides an eased
transition into the loading phase of the ETL process.
within the dimension providing multiple occurrences of a dimension member allowing for the history to be
preserved.
z Type III as data for columns of a dimension member change and if the data mart desires to preserve the
last version of that changed column, the original data is moved to a last version column on the dimension
record and all new dimension information overwrites the existing columns.
Note In general terms and specifically for this white paper, the Type III slowly changing
dimension is not being considered.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 13 de 69
The multiphase data pump is a feature introduced with SQL Server 2000 that provides even greater flexibility to
using the DTS data pump to move data between data sources. The Data Pump now supports phases that occur
prior to the sourcing of data, during the transformation of a row, after the transformation of a row, at the
completion of a batch of rows, after the last data has been read from the data source and at the completion of
the data pump operation. These phases are exposed and are capable of having script associated within them
through use of the ActiveX Script Transformation.
While the processing of data using ActiveX Script transformations was remarked as the least favorable in
transforming large quantities of data, the specific process of loading dimension records is generally less data
intensive. Given this, the techniques presented in this section offer a preferred approach to managing dimension
change and leveraging the intrinsic features of DTS in doing so.
New dimension members are inserted into the production dimension table
2.
Existing dimension members that have one or more changed columns are updated
3.
Existing dimension members that have not changed do not need any modification but can be overwritten to
simplify the logic.
These three steps in the loading of the dimension are readily supported by the functions of DTS. DTS provides
the Data Driven Query task and Lookups to allow for the conditional inserting, updating or skipping of rows.
The illustration below depicts the DTS package workflow for performing the dimensional load.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 14 de 69
New dimension members are inserted into the production dimension table
2.
Existing dimension members that have one or more changed columns are flagged as no longer being the
current version and are given an expiration date.
3.
For the changed dimension member, a new record is created to preserve history and it is identified as the
current record.
The achievement of these steps is done using a combined technique of comparing the checksum information
from the staging and production tables, assessing change and using the Transform Data task to insert new
records into the dimension table. One element that is not a feature of the Transform Data task is support for
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 15 de 69
updates. Use of a client-side, disconnected recordset will support the updates necessary in managing the
dimension change.
To begin, a package is created with a Transform Data task between two connections. The transformation for
the task is then modified to be an ActiveX Script transformation and the transformation code is as follows:
'constants for the COLUMNS
Const PRODUCTID_WK = 0
...
Const CURRENT_RECORD_IND = 20
Const EFFECTIVE_BEGIN_DATE = 21
Const EFFECTIVE_END_DATE = 22
Const CHECKSUM = 23
Dim
Dim
Dim
Dim
Dim
Conn
Rs
nRowsInserted
nRowsSkipped
nRowsUpdated
Function PreSourceMain()
'Runs at the beginning of the transform task
nRowsInserted = 0
nRowsUpdated = 0
nRowsSkipped = 0
'We want to establish
'an ADO Disconnected Recordset
' Create instance of connection object and then open the
' connection.
Set Conn = CreateObject("ADODB.Connection")
Conn.Open "file name=" & DTSGlobalVariables("gsUDLFile").Value
' Create instance of recordset object and open the
' recordset object against a table.
Set Rs = CreateObject("ADODB.Recordset")
' Setting the cursor location to client side is important
' to get a disconnected recordset.
Rs.CursorLocation = adUseClient
'Load all of the current dimension records
Rs.Open "Select * from <production data mart dimension> " + _
" where Current_Record_Ind = 'Y' order by productid_nk ASC ", _
Conn, _
3, _
adLockBatchOptimistic
' Disconnect the recordset.
Set Rs.ActiveConnection = Nothing
Conn.Close
If Rs.EOF And Rs.BOF Then
Rs.Close
Set Rs = Nothing
Else
Rs.MoveFirst
'Put an index on the Disconnected Recordset
Rs.Fields(PRODUCTID_NK).Properties("Optimize") = True
End If
PreSourceMain = DTSTransformstat_OK
End Function
At the completion of the PreSource phase of the data pump, an indexed, disconnected recordset is created for
the purpose of performing updates and leaving the data pump task only to perform INSERT operations. Using
the transform data task allows for the use of the fast load option. In most Type II dimensions, the majority of
the writing of data is inserting new records and not typically performing large quantities of updates.
The next phase to be examined is the row transform phase, which uses the Main() function for its logic. Within
this phase, the index is searched by natural key, the production record's checksum is compared to the staging
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 16 de 69
record's checksum and the maintenance logic described earlier is performed. The code illustrating this process
is:
Function Main()
'Runs for each ROW Based Transformation
If Not (Rs Is Nothing) Then
If Not Rs.BOF And Not Rs.EOF Then
Rs.MoveFirst
'Search for the record in the disconnected recordset
Rs.Find "productid_nk = " & DTSSource("ProductID_NK")
End If
If Not Rs.EOF Then
If (Rs.Fields(CHECKSUM).Value) = _
(DTSSource(CHECKSUM).Value) Then
'Skip the row because it is entirely the same
'Exit the function because there is no column
'mapping required
Main = DTSTransformStat_SkipRow
Exit Function
Else
'Mark the row as not current in the disconnected
'recordset as the new record has changed
'and the old record must be expired
Rs.Fields(EFFECTIVE_END_DATE).Value = Now
Rs.Fields(CURRENT_RECORD_IND).Value = "N"
End If
End If
End If
'Map the column values as all rows at this point are inserted
...
DTSDestination(PRODUCTID_NK) = DTSSource(PRODUCTID_NK)
'Set the effective start date for this dimension member
'and the effective end date to a VERY future date
'Make this record the CURRENT version
DTSDestination(EFFECTIVE_BEGIN_DATE) = Now
DTSDestination(EFFECTIVE_END_DATE) = "01/01/2075"
DTSDestination(CURRENT_RECORD_IND) = "Y"
Main = DTSTransformStat_InsertQuery
End Function
Through the course of the row transform phase, the Type II changes are maintained. The last essential step is
to make sure the updates performed against the client-side recordsets are written to the database. This will
happen in the Post Source phase of the data pump. The logic to reconnect the recordset and synchronize the
updated records is shown in the following code, the PostSourceMain() function.
Function PostSourceMain()
' Create instance of connection object and then open the
' connection.
Set Conn = CreateObject("ADODB.Connection")
Conn.Open "file name=" & DTSGlobalVariables("gsUDLFile").Value
If Not (Rs Is Nothing) Then
' Connect the recordset.
Set Rs.ActiveConnection = Conn
'Push all of the updates back to the server
Rs.UpdateBatch
Rs.Close
Conn.Close
'Cleanup
Set Rs = Nothing
Set Conn = Nothing
End If
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 17 de 69
PostSourceMain = DTSTransformstat_OK
End Function
As the Post Source phase of the data pump completes, all data is successfully updated within the dimension.
The use of the disconnected recordset offers an increase in the performance over the Data Driven Query
approach. While the latter approach was used to show Type II dimension change management, a Type I
dimension could use this approach as well.
the read and write operations of the data pump are not serialized from using the same connection for
performing lookups.
z Use the checksum or binary checksum functions to dramatically simplify the comparison logic for Type II
updates.
z Store connection information within UDL files so that the reconnection of a recordset can be achieved by
using a connection opened on the UDL file. Doing so will limit the potential of hardcoding the connection
information within the DTS package and requires that only the path to the UDL file's location is stored as
metadata in a global variable.
z Perform all other data transformations to dimension members prior to attempting the loading to simplify
Following the load of all dimensions, the process of loading the fact data for the BI solution is the final step for
completing the loading of the relational data store.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 18 de 69
loaded dimension members. Establishing this relationship is as straight forward as performing a join to the
production dimension table from the staging fact table on the natural key column(s).
Data Pump Options Insert Batch Size
One of the primary drivers for using the data pump task is the ability to batch transactions. Modifying the
Insert Batch Size option of the data pump enables the batching of transactions. Provided with a value greater
than zero, the data pump will perform that specified quantity of inserts in a transactional batch. The batching of
transactions is an important element of scalability. This is especially true when loading large quantities of facts
and attempting to keep the overall transaction log size requirements small.
Breaking the overall inserts into batches has the same benefits as the approach to "chunking" described in the
transformation and cleansing approaches.
Limiting Indexes to Increase Speed
Loading fact data is one of the larger consumers of time in the BI solutions load window. A factor to consider, in
the earliest stages of designing the solution, is whether or not the relational data will be queried or if this data is
only meant to be a source to Analysis Services OLAP Cube architecture? If the latter is true, the opportunity to
eliminate all indexing on fact data exists. Within Analysis Services, a cube can have an optimized schema that
allows the cube to process ONLY the fact table's data and does not require joins to dimension tables as well.
The benefit of not having any indexes in place is a substantially two-fold (or more) increase in the loading of
data into the fact table. While auditing is discussed later in the white paper, there exists a requirement to index
an audit column on the fact table. Doing so allows for the backing out of one or more incremental loads of fact
data should anything go awry in the load process.
Process for Loading Fact Records
By performing a LEFT OUTER JOIN between the fact table and the dimension tables, this allows for the accurate
representation of missing dimension member keys. Missing dimension member keys can be checked for in the
SELECT clause using a CASE statement and the IS NULL evaluation. This check is performed in order to assign a
null key value for fact records with missing dimension keys to two special dimension records. These dimension
records are the "Invalid" and the "Unknown" dimension members. A sample Transact SQL statement is provided
below showing the join between a dimension table in production and a fact table in the staging area.
SELECT
FROM
DimensionKey = CASE
WHEN Dim.Key is null AND Fact.NaturalKey is null
THEN 0 /*Unknown Dimension Record Key*/
WHEN Dim.Key is null AND Fact.NaturalKey is not null
THEN -1 /*Invalid Dimension Record Key*/
ELSE Dim.Key END,
Fact.Measure1, Fact.Measure2
StagingDB..Fact LEFT OUTER JOIN
ProductionDB..Dimension ON (Fact.NaturalKey = Dim.NaturalKey)
The result of mapping the keys for existing and null values is completely accurate data, reflecting the overall
state of data quality, being inserted into the fact table.
The records returned from this join operation can then be loaded into the target fact table using the DTS Data
Pump. While it would be possible to use just Transact SQL and an INSERT statement, the ETL would then loose
control over how it handled single erroneous records or small batches with erroneous records. With the batch
loading facilities of the data pump operations, erroneous data can be isolated to a batch and the remainder of
the fact records can be loaded.
Guidelines for Fact Loading
In most ETL designs, the process for loading fact records is less complex than any other aspect of the ETL. The
approach presented here offers a solution for loading fact data fully or incrementally and readily supports the
loading of multiple fact table partitions for maximum scalability. Considering the elements presented in this
approach, here are some guidelines to contemplate when developing production fact loading ETL:
z If the relational data store includes multiple fact table partitions, each load thread should address a single
partition at a time. Try to avoid using conditional partition logic or fragmented fact data insertion to a view.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 19 de 69
z Be sure to have up-to-date statistics on the dimension table indexes either by running the UPDATE
STATISTICS statement following the data load or using the "Auto Update Statistics" database option.
z Because the batch commit size is being used to manage both the size of the batch inserted to the fact table
and the grain with which errors are captured, a reasonable balance between these two factors should be
established. Using a setting of 0 or 1, causing either a single batch or a batch per row should typically be
avoided.
z Consider loading of data to multiple fact partition tables to support the future pruning of the BI solution. If
an operational requirement is to keep 36 monthly partitions available then removing the 37th partition each
month is as easy as dropping that table and recreating the partitioning view.
Practice Summary
Benefits
Leveraging the approaches presented for the Extract, Transformation and Loading best practice will result in
many benefits for making operational data available through the SQL Server BI platform. The chief benefits of
this best practice are:
z Restartability
Extracting data to text files, transforming data within the staging area and loading data using the DTS Data
Pump provides for the ability to select a portion of this process as the "restart" point should problems exist.
By having data in text files, there is no need to diagnose data quality issues within the production source
system and more importantly there is no need to re-run the extracting from this source system if the
process needs to be restarted.
z Manageability
Defining transformations within the staging area and performing key lookups when loading insures that
these pivotal tasks of the ETL process are capable of being maintained.
z Comprehensive load functionality
Through blending of Transact SQL and the DTS Data Pump features, a loading solution ties together the
distinct features of these platforms and allows for a comprehensive approach, leveraging the right technical
characteristics of each.
z Control over reporting data quality
By indicating the most common data quality issues, like the "Invalid" and "Unknown" dimension members,
the DTS ETL solution plays a significant role in making the organization aware of common data quality
issues while not jeopardizing the availability of analytical data.
Precautions
The precaution areas for this practice and the approaches are limited but do exist. The key precaution area is:
z Reporting of Data Quality
While the reporting of data quality was mentioned as a benefit, organizations with significant dimension or
fact data quality issues may perceive the reporting of data in this way as a shortcoming of the BI solution.
Managing expectations around the data quality and establishing the perception of the correctness of this
approach makes certain that the organization sees the value in recognizing the existence of both quality
and inferior data.
Historically, the ETL processes were only concerned with making data available through the relational data mart
or data warehouse. Today, with the Data Warehousing Framework, the final destination for data in many BI
solutions is the Analysis Services platform. The next section discusses the role of managing Analysis Services
partitions as part of the DTS BI solution infrastructure.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 20 de 69
programmatically managing the structure of the OLAP database schema and the functions of the analysis
server. Elements, such as managing aggregations on partitions (including usage-based optimizations),
dynamically controlling access to OLAP objects through security roles, performing an archival of an OLAP
database, and managing the lifecycle of other OLAP objects such as linked cubes, are all accessible through
these interfaces and worthy of automation within the Data Warehousing Framework (not to mention their own
white paper). This section focuses on the role of Decision Support Objects, one Analysis Services interface, and
the DTS Analysis Services' Processing task (built on top of Decision Support Objects) as two technologies to
begin automating the management of Analysis Services.
Creating Partitions
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 21 de 69
The process of creating partitions is one of the more common scenarios for using DSO within DTS. Automating
the OLAP partition creation process can allow the Analysis Services cube and multi-dimensional data store to
evolve with the relational data in the BI solution. The driver for using DTS to create a new OLAP partition is
often the need to support managing the OLAP schema dynamically in response to the changes in the relational
data store.
The below script can be placed within any ActiveX Script object (typically used in an ActiveX Script task) and
can be used to create an OLAP Partition.
Function CreatePartition
Dim objServer
Dim objDB 'A DSO.MDStore
Dim oCube 'A DSO.MDStore
Dim oPart 'A DSO.MDStore
Cloning Partitions
A cloned partition, as the name implies, is a partition that is a copy of a pre-existing OLAP partition. Cloning
partitions is important when programmatically managing partitions that have underlying aggregations. As the
overall partition management approach is explored more, the relevance of partition cloning will become all the
more clear. The first step, however, to explaining the benefits of cloning partitions, with DSO and DTS, is to
explore an example of how to clone an existing partition within ActiveX Script in DTS.
Function ClonePartition(strServer, strDabase, strCubeName, _
strPartition, strBasedOnPartition, strSliceValue)
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
objServer
objDB 'A DSO.MDStore Object
oCube 'A DSO.MDStore Object
oPart 'A DSO.MDStore Object
objClonePart 'A DSO.MDStore Object
objSourcePartDimension 'A DSO.Dimension Object
objSourcePartLevel 'A DSO.Level object
lngDim
lngLev
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 22 de 69
objClonePart = nothing
objPart = nothing
objCube = nothing
objDB = nothing
objServer = nothing
Function
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 23 de 69
strSliceValue = _
Trim(Mid(pstrSliceValue, lngStringPosition + 1, _
Len(pstrSliceValue) - (lngStringPosition)))
astrLevelSlices = Split(strSliceValue, ".")
For lngLevel = LBound(astrLevelSlices) To UBound(astrLevelSlices)
If objDimension.Levels.Count - 1 < lngLevel Then
Exit Function
Else
Set objLevel = oDimension.Levels(lngLevel + 1)
objLevel.SliceValue = astrLevelSlices(lngLevel)
End If
Next
ApplySliceValue = True
End Function
The approach to cloning partitions is somewhat similar to the approach for creating partitions with a few
exceptions. In creating a partition, a check is performed to see that no other partition of the same name exists.
In cloning a partition, a check is performed to make sure that the other partition does exist. Additionally, the
slice information is generally updated for the cloned partition to avoid duplication of data within the OLAP cube.
The result of cloning a partition is two partitions are of the same structure, with differing slice values, allowing
for their assimilation, or Merging, in the future.
Merging Partitions
While the partition management approach has focused on creating and cloning partitions to dynamically grow
alongside of the relational data store, there is an equally compelling reason to Merge partitions once they are no
longer the analytical "hot spots" within the cube. DSO provides the capability to merge two partitions of the
same structure with the same or no aggregations. DTS makes the process of achieving this within BI solution
architectures relatively easy, programmatically.
The example script below merges two partitions, a source and a target partition into each other.
Function MergePartitionsbyName(
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
Dim
strDatabase, _
strCubeName, _
strSourcePartition, _
strTargetPartition, _
objServer)
MergePartitionsByName = False
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 24 de 69
Exit Function
End If
'Checking if the partitions exist
If objCube.MDStores.Find(strSourcePartition) Then
Set objSourcePart = objCube.MDStores(strSourcePartition)
Else
Set objCube = Nothing
Set objDB = Nothing
Set objServer = Nothing
Exit Function
End If
If objCube.MDStores.Find(strTargetPartition) Then
Set objTargetPart = objCube.MDStores(strTargetPartition)
Else
Set objCube = Nothing
Set objDB = Nothing
Set objServer = Nothing
Exit Function
End If
Under DSO, partitions with differing slices cannot be merged together. This is overcome programmatically by
first removing the slices from each partition, merging them, and then reapplying an applicable slice value.
'Loop through the levels purging each slice value from the source
'As the slice value will need to be rebuilt
For lngDim = 1 To objSourcePart.Dimensions.Count
Set objSourcePartDimension = objSourcePart.Dimensions(lngDim)
For lngLev = 1 To objSourcePartDimension.Levels.Count
Set objSourcePartLevel = objSourcePartDimension.Levels(lngLev)
objSourcePartLevel.SliceValue = ""
Next
Next
'Loop through the levels purging each slice value from the target
'As the slice value will need to be rebuilt
For lngDim = 1 To objTargetPart.Dimensions.Count
Set objTargetPartDimension = objTargetPart.Dimensions(lngDim)
For lngLev = 1 To objTargetPartDimension.Levels.Count
Set objTargetPartLevel = objTargetPartDimension.Levels(lngLev)
objTargetPartLevel.SliceValue = ""
Next
Next
set objSourcePartDimension = nothing
set objSourcePartLevel = nothing
set objTargetPartDimension = nothing
set objTargetPartLevel = nothing
objTargetPart.Merge strSourcePartition
'Apply the new slice value
'Assumes Slice Value is fully qualified (i.e. "Calendar=All
Years.1997.1.January.3" for January 3rd, 1997)
call ApplySliceValue(objTargetPart, CStr(strSliceValue))
objCube.Update
objServer.Refresh
MergePartitionsByName = True
'Perform Cleanup
Set oSourcePart = Nothing
Set oCube = Nothing
Set oDB = Nothing
Set oServer = Nothing
Exit Function
Merging partitions through DTS and DSO solves the architectural dilemma of managing partition explosion, the
increase in numbers of partitions over time, and establishes a clear path for pruning your OLAP data through the
dropping of partitions.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 25 de 69
Dropping Partitions
While the approach reported here is about dropping OLAP partitions using DSO and DTS, the approach's mantra
is solving the challenge of sustaining the availability of data, which is meaningful to the users of the BI
solution, and eliminating the data, which is no longer analytically viable. As a result, the task of dropping
partitions often coincides with the removal or pruning of old, meaningless fact data from the relational data
store, which hopefully the DTS architecture controlled, as well.
Dropping a partition is actually one of the easier programmatic operations with DSO. The actual code to drop a
partition is:
Function DeletePartition(strDatabase, _
strCubeName, _
strPartition, _
objServer)
Dim objDB 'A DSO.MDStore
Dim objCube 'A DSO.MDStore
Dim objPart 'A DSO.MDStore
DeletePartition= False
'Checking if the database is valid
If objServer.MDStores.Find(strDatabase) Then
Set objDB = objServer.MDStores(strDatabase)
Else
DeletePartition= False
Set objServer = Nothing
Exit Function
End If
'Checking if the cubename is valid
If objDB.MDStores.Find(strCubeName) Then
Set objCube = objDB.MDStores(strCubeName)
Else
Set objDB = Nothing
Set objServer = Nothing
DeletePartition= False
Exit Function
End If
'Checking if the partitions exist
If objCube.MDStores.Find(strPartition) Then
Set objPart = objCube.MDStores(strPartition)
Else
Set objCube = Nothing
Set objDB = Nothing
Set objServer = Nothing
DeletePartition = False
Exit Function
End If
'Checking if the partition exists
If objCube.MDStores.Find(strPartition) Then
If objCube.MDStores.Count = 1 Then
'Cannot delete the last partition of a cube
Set objCube = Nothing
Set objDB = Nothing
Set objServer = Nothing
DeletePartition = False
Exit Function
End If
End If
objCube.MDStores.Remove (strPartition)
End If
objCube.Update
DeletePartitionbyName = True
'Perform Cleanup
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 26 de 69
to manage Analysis Services installed on a machine outside of the context of the local machine where the
SQL Server Agent is running.
z The SQL Server Agent service account whether found on the local machine or on the domain, must be a
member of the Analysis Server's local "OLAP Administrators" group prior to executing a DTS package
leveraging DSO.
z During the initial phases of a BI solution, it is very likely that merging partitions will be impossible due to
usage based optimizations and other initial OLAP design strategies for increasing the performance being
implemented.
z Use DTS to prevent the scenario of orphaned OLAP partitions with no underlying relational data to support
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 27 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 28 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 29 de 69
By executing the depicted package using DTSRUN, the single threading requirements for the Analysis Services
processing task and the Execute Package task are overcome. This is due to the main DTS package executing
the Execute Process task creating an independent Win32 process space with its own threading. Within the
independent Win32 process space the entire OLAP processing package executes. This approach allows for the
processing of multiple OLAP partitions or objects from the same root DTS package, through new DTS Package
process spaces instantiated by multiple concurrent Execute Process tasks.
strServerName = DTSGlobalVariables("ServerName").Value
strOLAPDBName = DTSGlobalVariables("OLAPDBName").Value
strCubeName = DTSGlobalVariables("CubeName").Value
strPartitionName = DTSGlobalVariables("PartitionName").Value
'Build the hierarchical treekey for a partition
'ServerName\DBName
strTreeKey = strServerName & "\" & strOLAPDBName & _
"\CubeFolder\" & strCubeName & "\" & strPartitionName
'Place the TreeKey in the Global Variable
DTSGlobalVariables("TreeKey").Value = strTreeKey
The above script, executed within an ActiveX Script task, would be followed by a Dynamic Properties task to
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 30 de 69
assign the global variable, TreeKey, to the Analysis Services Processing task's TreeKey property. The
Analysis Services Processing task would then use this property to process the object as part of the
encapsulated OLAPProcess package mentioned earlier.
other non-processing functions can be undertaken, including creating local cubes, establishing security
roles, changing data sources for connections, and table sources for dimensions and partitions.
z Invest in using the stock Analysis Services Processing task whenever you can. Re-inventing the wheel
for Analysis Services processing with other approaches like DSO is not the ideal approach.
z Do not overlook the power of manipulating the properties for the Analysis Services Processing task.
z Use the Dynamic Properties task and global variables to manipulate the Analysis Services Processing
task. Otherwise, programmatically manipulating the task through the DTSPackage object model will
require the task's properties() collection be referenced by ordinal value.
z Change the Dynamic Properties task's workflow properties to execute on the main thread otherwise
Practice Summary
Benefits
Managing the Analysis Services platform from within DTS as a best practice has many benefits. The most
noteworthy of these are:
Repeatable extensibility
The practice extends the ETL processing to the presentation tier of the BI architecture, providing a repeatable
approach for achieving the goal of making meaningful, timely business analytics available for consumption
directly following the load of the relational data store.
Success through autonomy
Processing cubes, partitions and dimensions in a programmatic fashion establishes the foundation for an
independent approach to loading the data mart with no cross data mart or BI solution dependencies.
Automation without error
The approaches explored in this practice showcased the potential of automating less than simple processes.
Relying on the only other approach for managing Analysis Services, the administrative user, invites more risk to
the process than most people are comfortable with taking in a production system.
Precautions
The precaution areas for this practice and the approaches are limited but do exist. The key precaution area is:
Increased Availability
The speed with which analytical data in the BI solution can be delivered through automated Analysis Services
processes puts a strong requirement on creating the right procedures in the relational data store's loading to
make certain less than desirable data does not get to the OLAP presentation elements of the solution.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 31 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 32 de 69
Lineage information provides the means for determining the source of data, be it a table and column in a
relational schema, or the package that caused the data to be recorded. Through data lineage, we have unique
insight into the definition of data elements within schemas, also known as metadata, and their utilization in
packages. Through the recording of this lineage information, provided as variables, we can accurately track how
the schema elements are delivered to targets through DTS packages, the workhorses of data extraction,
transformation and loading. This type of information provides insight into data issues resulting from changes in
our package architectures.
Lineage in Two Forms
Lineage takes on two distinctly different forms in DTS. DTS implements column level lineage (also referred to as
Catalog metadata) through the scanning of schema information from OLE DB compliant data sources at the time
of transformation. The Catalog information is persisted for later reference within SQL Server and Meta Data
Services.
The second form of lineage in DTS is that of a package execution, each time a package executes, and if the
feature options are chose, DTS makes lineage identifiers for the particular package available to tasks.
Global Lineage Variables
Lineage variables, which relate to a package's execution, are available within the global variables of the DTS
package. These global variables are made available by selecting the Advanced tab of the Package Properties
dialog, and then choosing the Show lineage variables as source columns option. The global variables are
named DTSLineage_Short, an integer representation of the package lineage and DTSLineage_Full, a GUID
(globally unique identifier) representation of the package lineage, or the current execution.
Note A DTS Package doesn't need to be stored within Metadata services to leverage these
global variables.
Lineage and Auditing
Lineage information is captured at the time a package execution is logged, as well as when steps execute. This
information is persisted in the system tables of the MSDB database. The audit tables, where this information is
found as both a GUID and integer, are sysdtspackagelog and sysdtssteplog.
Including Logging Information in your Transforms
If Show Lineage variables as source columns is enabled, when the data transformation task is created,
both DTSLineage_Full and DTSLineage_Short will appear as source columns. These variables can be assigned as
columns of data to be inserted or updated along with the other columns in order to track each row's data
lineage. The illustration below depicts using the logging global variables in this way.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 33 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 34 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 35 de 69
To enable step-based error handling, right-click the task. On the shortcut menu, click Workflow, and then click
Workflow Properties. On the Options tab, select the Fail package on step failure checkbox as shown in
Figure 15.
The On Completion workflow ensures that subsequent tasks will be executed regardless of the preceding
task(s) outcome. This really means that the error is really being ignored and not really handled. This may
be the appropriate workflow in some cases, but in most cases, the BI solution may want to handle the error
more explicitly.
z On Failure
The On Failure workflow is followed whenever a task fails for any reason and neither Fail package on first
error nor Fail package on step failure is set. If either is set, they both take precedence over any further
activity in the package, and thus, the On Failure task is never executed.
Choosing the Right Combination
One of the powerful elements of DTS is the capability to manipulate its object model using an ActiveX Script
task. Since many of the DTS packages in the BI solution are originally invoked from external applications, each
package should return the correct return code. The only way to manage this, but still have some control over
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 36 de 69
fail on the first error if the package is being called from SQLAgent, DOS batch files, or any other application
that expects a return code.
Following these guidelines will make certain that the approach to managing error handling is successful.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 37 de 69
This example illustrates how the developer of the BI solution is allowed to implement a rich environment for
logging information and errors to the DTS logging destinations.
Practice Summary
Benefits
Managing Auditing and Error Handling from within DTS offers many options for implementation depending on
the level of functionality and coverage desired.
Among some of the main benefits of implementing auditing and error handling include:
z Data validation capabilities using auditing checks and balances
z More precise control over error handling and how DTS responds to errors
z Rich information captured during logging to make error resolution easier
z Using and capturing data lineage information to each piece of data can be tracked back to the source
z DTS can log events and errors to locations that make error management possible by external applications
Precautions
The main precaution area to remember is that while using external components to handle auditing and logging,
a level of complexity is added to the overall solution. Remember to document thoroughly any components and
code so that other developers can follow and resolve issues.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 38 de 69
logic within the Execute() method and adding extended, developer defined properties to the task. The
properties are often needed to achieve the additional logic.
CustomTaskUI Interface
To deliver a customized user interface for the task's property pages requires an implementation of the
DTS.CustomTaskUI COM interface. Doing so, allows the developer to create rich user interfaces to support the
definition of properties for the custom task.
PersistPropertyBag Interface
The final interface to be discussed in delivering the Visual Basic .NET custom task is the
DTS.PersistPropertyBag COM interface. The PersistPropertyBag interface provides an interface that DTS
will use to load the task's properties from and save the task's properties within the underlying package
structure, as appropriate.
Note At the time of this writing, for the Visual Basic .NET implementation of a custom task, all
three of these interfaces are required to deliver a comprehensive custom task to integrate within
the DTS portion of the BI Solution.
Visual Basic .NET and Component Object Mode (COM) Interoperability
A key element to understanding the nuances of developing the Visual Basic .NET custom task is the
interoperability layer between COM and the Common Language Runtime of the .NET Framework. In order for
the Visual Basic .NET class to implement the prescribed DTS COM interface, this interoperability (or interop)
layer must be defined through the creation of a Runtime Callable Wrapper (or RCW) for Visual Basic .NET to
utilize the COM interface as a .NET assembly. The opposite is true for DTS, a collection of COM servers, to use
the Custom Task's Visual Basic .NET assembly. A COM Callable Wrapper (or CCW) must be established for DTS
to interact with the Visual Basic .NET assembly. The graphic below provides an illustration of the interoperability
between the two platforms.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 39 de 69
Assembly registration tool (REGASM.exe) provides the ability to register the .NET assembly within the
registry so that a COM component could utilize the interfaces provided by the assembly.
Global Assembly Cache tool (GACUTIL.exe) provides a registration of the wrappers into the Global
Assembly Cache for the final step in interoperability between DTS and the Visual Basic .NET custom task.
Each of these tools has its place in the process of coding the Visual Basic .NET custom task.
Coding the Visual Basic .NET Custom Task
The custom task example being developed for this best practice is an Error Handler custom task. The behavior
of this task, shown in the package illustration below, is to retrieve the error information from the preceding
step, defined by an OnFailure workflow constraint, and log it to a textual log file, the Windows event log, or
both.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 40 de 69
Figure 19. Establishing the reference to the RCW (click image to see larger picture)
Implementing the Right Interfaces
Earlier in this best practices section, it was noted that the custom task class must implement three interfaces.
This class, named EHTask, begins with the implements declaration.
Public Class EHTask
'You must implement the CustomTask,
'CustomTaskUI and PersistPropertyBag interfaces
Implements Interop.DTS.CustomTask
Implements Interop.DTS.CustomTaskUI
Implements Interop.DTS.PersistPropertyBag
These three implements statements set the basis for the task development, including the implementation of all
required properties and methods of each interface. Before continuing with that step, it is a good idea to create
private variables to hold the values of the public properties of the task. Here is the variable declaration section
for the EHTask class.
'Create private variables to hold the standard properties
Private _Name As String
Private _Description As String
'Create a private reference to the task object
Private _TaskObject As Interop.DTS.Task
'Create
Private
Private
Private
Private
Private
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 41 de 69
The first area of focus is the code to support the standard properties.
Public Property Description() As String _
Implements Interop.DTS.CustomTask.Description
Get
Return _Description
End Get
Set(ByVal Value As String)
_Description = Value
End Set
End Property
Public Property Name() As String Implements Interop.DTS.CustomTask.Name
Get
Return _Name
End Get
Set(ByVal Value As String)
_Name = Value
End Set
End Property
Additional properties required for the .NET Error Handler custom task are:
z HandledStepName the internal name for the step, which the custom task will interrogate through the
LogToEventLog properties should be pulled from global variables within the package. Given that there will
likely be more than one error handler in the DTS package, this property makes certain that all .NET Error
Handler tasks use the same settings.
Following the standard properties, Description and Nameand the properties domain to the individual custom
taskis the standard Execute() method. Below is the entire code listing for the method, followed by
explanations of the flow and subroutines called within it.
Public Sub Execute(ByVal
ByVal
ByVal
ByRef
pPackage As Object, _
pPackageEvents As Object, _
pPackageLog As Object, _
pTaskResult As Interop.DTS.DTSTaskExecResult) _
Implements Interop.DTS.CustomTask.Execute
Dim
Dim
Dim
Dim
objPackage As Interop.DTS.Package
objTasks As Interop.DTS.Tasks
objStep As Interop.DTS.Step
objPackageLog As Interop.DTS.PackageLog
Dim
Dim
Dim
Dim
strSource As String
lngNumber As Long
strDescription As String
strErrorString As String
Try
'Cast the passed params into the
'local stronger typed variables
objPackage = pPackage
objPackageLog = pPackageLog
'Make sure we have a precedence step
Call EstablishPrecedence(objPackage)
'Check the HandledStepName and Throw an Exception
If Me.HandledStepName = "" Then
Throw New System.Exception( "Task cannot execute due to
no Precedence Constraint being defined.")
End If
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 42 de 69
The only other method to be implemented is the Properties property method for accessing the properties
collection of the custom task.
In the .NET Error Handler example, the properties collection is populated via the implementation of a
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 43 de 69
PropertiesProvider. This provider fills a properties collection through the GetPropertiesForObject method
call.
Public ReadOnly Property Properties() As Interop.DTS.Properties _
Implements Interop.DTS.CustomTask.Properties
Get
'Declare variables for Properties collection
'and ProviderClass to retrieve property info
Dim objProperties As Interop.DTS.Properties
Dim objPropProvider As _
Interop.DTS.PropertiesProviderClass = _
New Interop.DTS.PropertiesProviderClass()
'Using the reference to the existing
'task object, get a reference to the task object
'to pass to the Properties Provider
objProperties = objPropProvider.GetPropertiesForObject(_TaskObject)
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 44 de 69
End Sub
Within the New method, properties of the task are preset and the user interface is presented to the user for the
first time. Below are the UI elements of the custom task.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 45 de 69
The dialog above notifies the user anytime that the global variables are updated upon closing the Properties
dialog for the custom task.
DTS.PersistPropertyBag Interface
The DTS.PersistPropertyBag interface is an essential interface to the properties stored with the package. This
is solely the case when dealing with properties that are not being exposed by the DTS.CustomTask properties
collection. This is true with the .NET Error Handler custom task. Through the implementation of the
PersistPropertyBag interface, however, all properties that are defined for the custom task are capable of
being saved and loaded. The two methods required for the PersistPropertyBag interfaces implementation are
listed below.
Public Sub Load(ByVal PropertyBag As Interop.DTS.PropertyBag) _
Implements Interop.DTS.PersistPropertyBag.Load
'Create all of the PropertyBag readers to read information
'from the PropertyBag into the class level variables
_Name = PropertyBag.Read("Name")
_Description = PropertyBag.Read("Description")
_LogFileName = PropertyBag.Read("LogFileName")
_LogToEventLog = PropertyBag.Read("LogToEventLog")
_LogToFile = PropertyBag.Read("LogToFile")
_HandledStepName = PropertyBag.Read("HandledStepName")
_UseGlobals = PropertyBag.Read("UseGlobals")
End Sub
Public Sub Save(ByVal PropertyBag As Interop.DTS.PropertyBag) _
Implements Interop.DTS.PersistPropertyBag.Save
'Create all of the PropertyBag writers to persist information
'from the class level variables into the property bag
PropertyBag.Write("Name", _Name)
PropertyBag.Write("Description", _Description)
PropertyBag.Write("LogFileName", _LogFileName)
PropertyBag.Write("LogToEventLog", _LogToEventLog)
PropertyBag.Write("LogToFile", _LogToFile)
PropertyBag.Write("HandledStepName", _HandledStepName)
PropertyBag.Write("UseGlobals", _UseGlobals)
End Sub
Develop the custom task using Visual Basic .NET as prescribed in the prior section and Appendix B.
2.
3.
Register the Assembly, using the Assembly Registration Tool, for the resulting .NET DLL (somewhat similar
to Regsvr32.exe).
For example:
C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\RegAsm.exe
"C:\dotNetErrorHandler\bin\dotNetErrorHandler.dll"
4.
Register the assembly using the Assembly Registration Tool, for the Runtime Callable Wrapper, which
provides the .NET and COM interoperability, for the DTS Package Object library.
For example:
C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\RegAsm.exe
"C:\dotNetErrorHandler\Interop.DTS.dll"
5.
Add the registered assemblies from Steps 3 and 4 to the .NET Global Assembly Cache (GAC), using the
Global Assembly Cache tool.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 46 de 69
For example:
"C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Bin\gacutil.exe"
/i "C:\ dotNetErrorHandler \bin\ dotNetErrorHandler.dll"
and then
"C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Bin\gacutil.exe"
/i "C:\ dotNetErrorHandler \Interop.DTS.dll"
Note Each time the solution is re-built; the first command placing the .NET assembly into
the GAC will have to be run.
6.
Now the registry will have to be edited, as there is no present way to register a .NET custom task via the
DTS user interface. It is worth noting that users who are not familiar with editing the registry should not
attempt this as it can have less than desirable results.
The following items will need to be known before editing the registry:
z Full Path to the DLL (i.e., C:\dotNetErrorHandler\bin\dotNetErrorHandler.dll)
z Full Path to a DLL or .ICO file with an icon as the resource (optional)
z Description of the task (kept short i.e., .NET Error Handler)
z The GUID for the DLL The GUID can be found for the assembly in the AssemblyInfo.vb file under the
entry:
<Assembly: Guid("GUID DEFINED HERE")>
z ProgID for the task (i.e., the way this object would be called from CreateObject under COM, for
example, "dotNetErrorHandler.EHTask")
Once all of the above items have been established, a registry entries file is ready to be created to update
the registry. The template registry entries file for this approach is:
Windows Registry Editor Version 5.00
HKEY_CLASSES_ROOT\CLSID\{<The GUID>}]
@="<The Prog ID>"
"AppID"="{<The GUID>}"
"DTSIconFile"="<Path to the DLL>"
"DTSIconIndex"=dword:00000000
"DTSTaskDescription"="<The Task Description>"
[HKEY_CLASSES_ROOT\CLSID\{<The GUID>}\Implemented Categories]
[HKEY_CLASSES_ROOT\CLSID\{<The GUID>}\Implemented Categories\
{10020200-EB1C-11CF-AE6E-00AA004A34D5}]
[HKEY_CLASSES_ROOT\CLSID\{<The GUID>}\Implemented Categories\
{40FC6ED5-2438-11CF-A3DB-080036F12502}]
[HKEY_CLASSES_ROOT\CLSID\{<The GUID>}\InprocServer32]
@="<Path to the DLL>"
"ThreadingModel"="Both"
[HKEY_CLASSES_ROOT\CLSID\{<The GUID>}\ProgID]
@="<The PROGID>"
[HKEY_CLASSES_ROOT\CLSID\{<The GUID>}\Programmable]
[HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server
\80\DTS\Enumeration\Tasks\<The GUID>]
@="<The PROGID>"
Below are the contents of the actual registry entries file for the example custom task. These contents can
be copied to text editor and saved to TaskReg.reg or another suitable .reg filename.
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\CLSID\{EF4AC3E4-3D72-4117-AB91-8B417826792F}]
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 47 de 69
@="dotNetErrorHandler.EHTask"
"AppID"="{EF4AC3E4-3D72-4117-AB91-8B417826792F}"
"DTSIconFile"="C:\\dotNetErrorHandler\\ErrorHandler.ICO"
"DTSIconIndex"=dword:00000000
"DTSTaskDescription"=".NET Error Handler"
[HKEY_CLASSES_ROOT\CLSID\{EF4AC3E4-3D72-4117-AB91-8B417826792F}
\Implemented Categories]
[HKEY_CLASSES_ROOT\CLSID\{EF4AC3E4-3D72-4117-AB91-8B417826792F}
\Implemented Categories\{10020200-EB1C-11CF-AE6E-00AA004A34D5}]
[HKEY_CLASSES_ROOT\CLSID\{EF4AC3E4-3D72-4117-AB91-8B417826792F}
\Implemented Categories\{40FC6ED5-2438-11CF-A3DB-080036F12502}]
[HKEY_CLASSES_ROOT\CLSID\{EF4AC3E4-3D72-4117-AB91-8B417826792F}
\InprocServer32]
@="C:\dotNetErrorHandler\bin\dotNetErrorHandler.dll"
"ThreadingModel"="Both"
[HKEY_CLASSES_ROOT\CLSID\{EF4AC3E4-3D72-4117-AB91-8B417826792F}\ProgID]
@="dotNetErrorHandler.EHTask"
[HKEY_CLASSES_ROOT\CLSID\{EF4AC3E4-3D72-4117-AB91-8B417826792F}
\Programmable]
[HKEY_CURRENT_USER\Software\Microsoft\Microsoft SQL Server
\80\DTS\Enumeration\Tasks\EF4AC3E4-3D72-4117-AB91-8B417826792F]
@="dotNetErrorHandler.EHTask"
7.
Open the DTS Designer. The custom task should now be visible as a registered entry in the Task Toolbar.
using Visual Basic .NET gives the developer the ability to create custom tasks that do not need to execute
on the main thread as the Visual Basic .NET solution is free threaded and does not suffer from thread
affinity.
z In terms of developing the custom task, start slow. Create a base shell for the custom task, compile and
register it with DTS using the approaches described here. Once the foundation is in place, developing and
deploying updated features is the next incremental step.
z Consider building the task using Visual Basic 6.0. Why? One, it is a good language that allows for the eased
development of a custom task. Two, it provides a starting point for learning the differences between COM
and .NET. Finally, doing so determines whether or not .NET needs to be used due to threading implications.
If the task can be run on the main thread with no issues, there will be less of a need to make migrating, to
a .NET custom task, a priority.
z As with new languages and frameworks, there can sometimes be elements that need work. In the .NET
Error Handler example, the task implemented the properties provider within the
DTS.CustomTaskUI.Properties() method. The main reason for this was a quirk with the example not
correctly allowing the DTS Design Environment to manage the properties. As of this writing, there is no
known way to resolve this dilemma.
z By all means, expect and look for ways to achieve the same functionality with less code. The .NET
Framework base classes are exceptionally rich and provide for a superior way of achieving Win32
functionality than solely using COM and the Win32 API (notice it took only three lines of .NET code to add
Windows event logging to the custom task!).
z Learn more about deploying a .NET custom task by exploring and saving a copy of the registry nodes that
may be affected by the deployment. The existing tasks within the registry can certainly portray the
necessary elements for being successful in registering a .NET custom task for use in DTS.
Following these guidelines will build a better foundation for developing a Visual Basic .NET custom task and
making the task a successful element of the overall BI Solution.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 48 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 49 de 69
One of the first steps to making ActiveX Script available is to understand that each task, Workflow or Transform
has an ActiveXScript property, which is accessible throughout the package object hierarchy. This property
provides a string populated with all of the accessed object's ActiveX script.
Having the script of another task in a string is the beginning phase of reusing ActiveXScript.
Execute() and eval()
The VBScript and JScript ActiveX scripting languages are used most commonly within DTS scripting. Each of
these languages provides for a runtime means of including script defined within a string.
In VBScript, this support is provided by the Execute() function. The Execute() function takes a string
consisting of VBScript commands as a single parameter. The commands and functions defined within the string
are included in the runtime environment and can be called like any other command. Below is an example of this
concept.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 50 de 69
and tasks.
These methods can be overcome partially through the modular development of Parent/Child packages and
further eliminated through the development of custom tasks. However, neither of these approaches can
eliminate this situation entirely. The real solution is to develop a single code base that can be included in
packages at runtime and referenced by the package's ActiveX Script components.
The Single Code Base Package
Below is an illustration of the example package for developing a single scripting code base.
objFSO
objFile
objPackage
objTask
strScript
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 51 de 69
objTask.CustomTask.ActiveXScript.Value = strScript
set
set
set
set
objTask = nothing
objPackage = nothing
objFile = nothing
objFSO = nothing
Main = DTSTaskExecResult_Success
End Function
Following the execution of the above script, the Code Library task should contain a copy of the data within the
text file. Before continuing on the workflow to the Create Partition task, it is important to understand the
choice for and configuration of the Code Library task.
Code Library Task
The Code Library ActiveX Script task acts as the runtime repository for the script loaded from the text file.
The reason for choosing the Code Library task approach is simply:
z The ActiveX Script task can hold a great deal of scripting text supporting the approach of loading large
debugging.
In order to use the ActiveX Script task for this purpose, it is advisable to change the entry function to
something other than Main(). This point will be clearer in the next task. Secondly, the step's workflow property
for Disable this Step should be set to true as is shown below.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 52 de 69
This latter step makes certain that the task will not be executed as it lives outside of the workflow of the other
tasks.
Create Partition Reusing Standardized Scripting
The Create Partition ActiveX Script task really begins to illustrate the power of re-usable code by showing a
dramatic reduction in overall code within the task for a less than simple function. Through reference of the Code
Library task and use of the Execute() function within VBScript, the contents of the Code Library tasks are
loaded dynamically into the runtime environment of the Create Partition task. Thus, allowing the task to
reference functions that are defined in the text file loaded previously.
Here is the code listing for the task:
Dim
Dim
Dim
Set
Set
strCommonScript
objPackage
objTask
objPackage = DTSGlobalVariables.Parent
objTask = objPackage.Tasks("DTSStep_DTSActiveScriptTask_3")
strCommonScript = objTask.CustomTask.ActiveXScript.Value
Execute(strCommonScript)
Function Main()
Dim strTreeKey 'The hierarchy of the OLAP Object to Process
'Run the Dynamically added function which gathers the parameters for
'global variables and builds a TreeKey for use in
'the Analysis Services Processing Task!
call CreatePartition(strTreeKey)
'Place the TreeKey in the Global Variable
DTSGlobalVariables("TreeKey").Value = strTreeKey
Main = DTSTaskExecResult_Success
End Function
The CreatePartition() logic is similar to the logic shown earlier in the white paper. This logic consists of a great
deal more code than the three lines of code it took here, within the Main function, to perform the partition
creation. By naming the entry function in the Code Library task by a name other than Main(), there were no
conflicts. However, had we tried to use the same entry function name after reading the ActiveX Script from the
Code Library task, conflicts would have existed prohibiting this reuse approach.
Guidelines
Delivering a reusable standardized scripting code base is actually a much easier task than some of the other
approaches a person might take, to leverage the intellectual property built up over time for doing scripting
within DTS. In order to gain value from the investments already made within the DTS architecture, there are a
few guidelines to keep in mind.
z Consider storing the ActiveX script in a text file or in multiple files. This promotes the control of the
scripting outside of the DTS environment and allows for the use of products like Visual Source Safe to
manage the versioning of the common script.
z Load the text file using the File System Object in lieu of other methods to avoid issues like contention and
File Locking.
z Strive for the utmost modularity. A reusable scripting function should pass parameters, definitely, or rely
upon settings within global variables, if absolutely necessary. It is important to not build dependencies
between a variable within the task and use of that variable within the dynamic script.
z Sometimes modularity can be better achieved in multiple DTS packages. Keep in mind that SQL Server
2000 provides even greater support for the nested child packages and the use of child packages may be a
more prudent solution for achieving reusability.
Practice Summary
Benefits
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 53 de 69
Enhancing the functionality of DTS results in an even more robust component of the SQL Server BI platform.
Some of the core benefits realized by these enhancement practices are:
z Modularity
Through implementation of the approaches shown, a more modular approach will be enforced in the
development of DTS packages resulting in other intrinsic benefits.
z Standardization
Employing these approaches will result in greater overall standardization of the DTS package architecture.
Through standardization greater efficiencies can and will be achieved in the overall development,
maintenance and execution of the DTS packages within BI solutions.
z Limitless Functionality
Through incorporation of the technical approaches discussed, many areas of other functionality can be
introduced through additional COM or .NET components. Integrating these components can and often will
far exceed the standard capabilities of traditional BI ETL platforms.
Precautions
A limited number of precautionary areas do exist for this practice. The main precaution to keep in mind is
complexity.
Complexity
Complexity chiefly results from mismanaged implementations of logic and taking a more reactive approach to
development than a proactive one. Using these techniques require the core investment of time in the design of
the solution, to establish the foundation for common logic built into reusable script and custom tasks.
Conclusion
DTS is a flexible architecture providing the opportunity to build comprehensive solutions within the Microsoft
Data Warehousing Framework. This white paper has highlighted the prominent best practices for using DTS
within BI solutions. Practical exploration of the best practices and approaches discussed will offer an opportunity
to enhance and tailor these techniques for the individual solution architecture.
http://www.microsoft.com/traincert.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 54 de 69
healthcare, finance, marketing, banking, technology, and sports and entertainment. He has experience in clickstream analytics, data mining, transactional application architecture, Internet application architecture, database
administration, and database design. He is also the co-author of SQL Server 2000 Data Transformation Services
from Wrox Press, and has authored many articles on business intelligence, SQL Server, DTS and Analysis
Services.
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 55 de 69
String)
Value
String)
objPackage As Interop.DTS.Package
objTasks As Interop.DTS.Tasks
objStep As Interop.DTS.Step
objPackageLog As Interop.DTS.PackageLog
Dim
Dim
Dim
Dim
strSource As String
lngNumber As Long
strDescription As String
strErrorString As String
Try
'Cast the passed params into the local stronger typed variables
objPackage = pPackage
objPackageLog = pPackageLog
'Make sure we have a precedence step
Call EstablishPrecedence(objPackage)
'Check the HandledStepName and Throw an Exception
If Me.HandledStepName = "" Then
Throw New System.Exception("Task cannot execute due to no
Precedence Constraint being defined.")
End If
'If the Task is defined to drive from the global variables
we need to check
Call ReadFromGlobalVariables(objPackage)
'Get a Step Object Reference
objStep = objPackage.Steps.Item(Me.HandledStepName)
'Retrieve the Error Information
Call objStep.GetExecutionErrorInfo(lngNumber, strSource,
strDescription)
'Build the Error String
strErrorString = Format(Now, "MM/dd/yyyy hh:mm:ss tt") & "|" & _
objPackage.Name & "|" & objStep.Name & "|" & _
" The Step, " & objStep.Description & _
" failed with the following error: " & _
lngNumber.ToString() & " - " & strSource & " - " & strDescription
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 56 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 57 de 69
Return _UseGlobals
End Get
Set(ByVal Value As Boolean)
_UseGlobals = Value
End Set
End Property
Public ReadOnly Property Properties() As Interop.DTS.Properties
Implements Interop.DTS.CustomTask.Properties
Get
'Declare variables for Properties collection and
ProviderClass to retrieve property info
Dim objProperties As Interop.DTS.Properties
Dim objPropProvider As Interop.DTS.PropertiesProviderClass =
New Interop.DTS.PropertiesProviderClass()
'Using the reference to the existing task object,
get a reference to the task object
'to pass to the Properties Provider
objProperties = objPropProvider.GetPropertiesForObject(_TaskObject)
'Perform some cleanup on the properties provider
objPropProvider = Nothing
'Return the value of the properties collection
Return objProperties
End Get
End Property
Public Sub Load(ByVal PropertyBag As Interop.DTS.PropertyBag)
Implements Interop.DTS.PersistPropertyBag.Load
'Create all of the PropertyBag readers to read information from the
'PropertyBag into the module level variables
_Name = PropertyBag.Read("Name")
_Description = PropertyBag.Read("Description")
_LogFileName = PropertyBag.Read("LogFileName")
_LogToEventLog = PropertyBag.Read("LogToEventLog")
_LogToFile = PropertyBag.Read("LogToFile")
_HandledStepName = PropertyBag.Read("HandledStepName")
_UseGlobals = PropertyBag.Read("UseGlobals")
End Sub
Public Sub Save(ByVal PropertyBag As Interop.DTS.PropertyBag)
Implements Interop.DTS.PersistPropertyBag.Save
'Create all of the PropertyBag writers to persist information from the
'the module level variables into the property bag
PropertyBag.Write("Name", _Name)
PropertyBag.Write("Description", _Description)
PropertyBag.Write("LogFileName", _LogFileName)
PropertyBag.Write("LogToEventLog", _LogToEventLog)
PropertyBag.Write("LogToFile", _LogToFile)
PropertyBag.Write("HandledStepName", _HandledStepName)
PropertyBag.Write("UseGlobals", _UseGlobals)
End Sub
Public Sub New()
End Sub
Public Sub Initialize(ByVal pTask As Interop.DTS.Task) Implements
Interop.DTS.CustomTaskUI.Initialize
_TaskObject = pTask
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub
Public Sub Edit(ByVal hwndParent As Integer) Implements
Interop.DTS.CustomTaskUI.Edit
'Should Show a UI Here
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 58 de 69
ShowPropertyUI()
End Sub
Public Sub GetUIInfo(ByRef pbstrToolTip As String, ByRef
pbstrDescription As String, ByRef plVersion As Integer, ByRef pFlags
As Interop.DTS.DTSCustomTaskUIFlags) Implements
Interop.DTS.CustomTaskUI.GetUIInfo
'Not Implemented
End Sub
Public Sub Delete(ByVal hwndParent As Integer) Implements
Interop.DTS.CustomTaskUI.Delete
_TaskObject = Nothing
End Sub
Public Sub Help(ByVal hwndParent As Integer) Implements
Interop.DTS.CustomTaskUI.Help
'Not Implemented
End Sub
Public Sub CreateCustomToolTip(ByVal hwndParent As Integer,
ByVal x As Integer, ByVal y As Integer, ByRef plTipWindow
As Integer) Implements Interop.DTS.CustomTaskUI.CreateCustomToolTip
'Not Implemented
End Sub
Public Sub New2(ByVal hwndParent As Integer) Implements
Interop.DTS.CustomTaskUI.New
'In order to implement the New Method we needed to declare this way
'Preset the Settings for the task
Me.LogToEventLog = True
Me.LogToFile = True
Me.LogFileName = ""
Me.UseGlobals = True
'Should Show a UI Here
ShowPropertyUI()
End Sub
Private Sub ShowPropertyUI()
'Handles the UI Property Page Display
Dim objForm As New frmProperty()
Dim objPackage As Object
Dim objTasks As Object
objForm.objCustomTask = Me
objForm.objMyTask = _TaskObject
Try
'Construct references to the Tasks Collection and the Package Object
objTasks = _TaskObject.Parent
objPackage = objTasks.Parent
'Determine if the global variables exist for the Error Handler
Call CheckGlobalVariables(objPackage)
'Read data from the global variables and assign to properties
Call ReadFromGlobalVariables(objPackage)
'Check for a precedenceconstraint
Call EstablishPrecedence(objPackage)
'Set a Friend declared boolean so we will know how the user
left the UI
bolUICancelled = True
'Tell the Form to load the properties before you show it
objForm.GetProperties()
'Show the Form
objForm.ShowDialog()
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 59 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 60 de 69
'If the task uses the values in the global variables then the
'values entered in
'the UI should be persisted to the GlobalVariables Collection
If Me.UseGlobals Then
'Oddity: The only way to get the globals to be
'accessible as their correct types (i.e. String and Booleand)
'is to remove and re-add them
objGlobalVariables.Remove("gstrErrorLogFile")
objGlobalVariables.AddGlobalVariable("gstrErrorLogFile",
CStr(Me.LogFileName.ToString))
objGlobalVariables.Remove("gbolErrorLogToEventLog")
objGlobalVariables.AddGlobalVariable("gbolErrorLogToEventLog",
CBool(Me.LogToEventLog))
objGlobalVariables.Remove("gbolErrorLogToFile")
objGlobalVariables.AddGlobalVariable("gbolErrorLogToFile",
CBool(Me.LogToFile))
'Let the user know that this action was performed
MsgBox("The .NET Error Handler global variables were updated",
MsgBoxStyle.Information, ".NET Error Handler")
End If
'Clean up and relegate to the GC
objGlobalVariable = Nothing
objGlobalVariables = Nothing
End Sub
Private Sub ReadFromGlobalVariables(ByVal pobjPackage As Interop.DTS.Package)
Dim objGlobalVariables As Interop.DTS.GlobalVariables =
pobjPackage.GlobalVariables
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 61 de 69
'If the task uses the values in the global variables then the values entered in
'the GlobalVariables should be assigned to the Task's properties
If Me.UseGlobals Then
Me.LogFileName = objGlobalVariables.Item("gstrErrorLogFile").Value
Me.LogToEventLog = objGlobalVariables.Item("gbolErrorLogToEventLog").Value
Me.LogToFile = objGlobalVariables.Item("gbolErrorLogToFile").Value
End If
End Sub
End Class
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 62 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 63 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 64 de 69
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 65 de 69
Me.lblVersion.Text = strVersion
End Sub
Public Sub SaveProperties()
'Map Form Elements to Task Properties
objCustomTask.Description = Me.txtDescription.Text
objCustomTask.Name = Me.txtName.Text
objCustomTask.LogFileName = Me.txtFileName.Text
objCustomTask.LogToEventLog = Me.chkLogToEvent.Checked
objCustomTask.LogToFile = Me.chkLogToFile.Checked
objCustomTask.UseGlobals = Me.ckhUseGlobals.Checked
End Sub
#End Region
Private Sub frmProperty_Closing(ByVal sender As Object, ByVal e As
System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
objMyTask = Nothing
objCustomTask = Nothing
'Clean up the global private references
objTasks = Nothing
objPackage = Nothing
End Sub
Private Sub btnOkay_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnOkay.Click
objCustomTask.bolUICancelled = False
Me.SaveProperties()
Me.Close()
End Sub
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnCancel.Click
Me.Close()
End Sub
Private Sub btnFileDialog_Click(ByVal sender As System.Object, ByVal e
As System.EventArgs) Handles btnFileDialog.Click
Dim objFileDialog As New Windows.Forms.SaveFileDialog()
'Configure the FileDialog
objFileDialog.DefaultExt = ".log"
objFileDialog.Filter = "Log Files (*.log)|*.log"
objFileDialog.FileName = Me.txtFileName.Text
objFileDialog.Title = ".NET Error Handler : Select Log File"
objFileDialog.ShowDialog()
If objFileDialog.FileName() <> "" Then
Me.txtFileName.Text = objFileDialog.FileName()
End If
objFileDialog = Nothing
End Sub
End Class
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 66 de 69
<xsd:choice maxOccurs="unbounded">
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"
msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string"
minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"
msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms,
Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms,
Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="lblVersion.Modifiers" type="System.CodeDom.MemberAttributes,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="txtName.Modifiers" type="System.CodeDom.MemberAttributes,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="txtDescription.Modifiers"
type="System.CodeDom.MemberAttributes, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="Label2.Modifiers" type="System.CodeDom.MemberAttributes,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="Label3.Modifiers" type="System.CodeDom.MemberAttributes,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="chkLogToEvent.Modifiers"
type="System.CodeDom.MemberAttributes, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="chkLogToFile.Modifiers"
type="System.CodeDom.MemberAttributes, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 67 de 69
</data>
<data name="txtFileName.Modifiers"
type="System.CodeDom.MemberAttributes, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="btnFileDialog.Modifiers"
type="System.CodeDom.MemberAttributes, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="btnOkay.Modifiers" type="System.CodeDom.MemberAttributes,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="btnCancel.Modifiers" type="System.CodeDom.MemberAttributes,
System, Version=1.0.3300.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="txtStepName.Modifiers"
type="System.CodeDom.MemberAttributes, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="ckhUseGlobals.Modifiers"
type="System.CodeDom.MemberAttributes, System, Version=1.0.3300.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>Assembly</value>
</data>
<data name="$this.Name">
<value>frmProperty</value>
</data>
</root>
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 68 de 69
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "1"
/>
<Config
Name = "Release"
BaseAddress = "285212672"
ConfigurationOverrideFile = ""
DefineConstants = ""
DefineDebug = "false"
Def race = "true"
DebugSymbols = "false"
IncrementalBuild = "false"
Optimize = "true"
OutputPath = "bin\"
RegisterForComInterop = "false"
RemoveIntegerChecks = "false"
TreatWarningsAsErrors = "false"
WarningLevel = "1"
/>
</Settings>
<References>
<Reference
Name = "System"
AssemblyName = "System"
/>
<Reference
Name = "System.Data"
AssemblyName = "System.Data"
/>
<Reference
Name = "System.XML"
AssemblyName = "System.Xml"
/>
<Reference
Name = "Interop.DTS"
AssemblyName = "Interop.DTS"
HintPath = "Interop.DTS.dll"
/>
<Reference
Name = "System.Drawing"
AssemblyName = "System.Drawing"
HintPath = "..\..\..\..\WINDOWS\Microsoft.NET\Framework
\v1.0.3705\System.Drawing.dll"
/>
<Reference
Name = "System.Windows.Forms"
AssemblyName = "System.Windows.Forms"
HintPath = "..\..\..\..\WINDOWS\Microsoft.NET\Framework
\v1.0.3705\System.Windows.Forms.dll"
/>
</References>
<Imports>
<Import Namespace = "Microsoft.VisualBasic" />
<Import Namespace = "System" />
<Import Namespace = "System.Collections" />
<Import Namespace = "System.Data" />
<Import Namespace = "System.Diagnostics" />
</Imports>
</Build>
<Files>
<Include>
<File
RelPath = "AssemblyInfo.vb"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "EHTask.vb"
SubType = "Code"
BuildAction = "Compile"
/>
<File
RelPath = "frmProperty.vb"
SubType = "Form"
BuildAction = "Compile"
/>
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004
Best Practices for Using DTS for Business Intelligence Solutions (Microsoft SQL... Pgina 69 de 69
<File
RelPath = "frmProperty.resx"
DependentUpon = "frmProperty.vb"
BuildAction = "EmbeddedResource"
/>
</Include>
</Files>
</VisualBasic>
</VisualStudioProject>
Average rating:
9 out of 9
123456789
4 people have rated this
page
Submit
http://msdn.microsoft.com/library/en-us/dnsql2k/html/sql_BusIntBPwithDTS.asp?fra...
18/06/2004