<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SSIS Talk &#187; SSIS Data flow</title>
	<atom:link href="http://www.ssistalk.com/category/ssis/ssis-data-flow/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.ssistalk.com</link>
	<description>Random thoughts and experiences with SSIS, by Phil Brammer</description>
	<lastBuildDate>Wed, 01 Feb 2012 12:48:29 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>SSIS &#8211; Export all SSIS packages from msdb</title>
		<link>http://www.ssistalk.com/2011/03/14/ssis-export-all-ssis-packages-from-msdb/</link>
		<comments>http://www.ssistalk.com/2011/03/14/ssis-export-all-ssis-packages-from-msdb/#comments</comments>
		<pubDate>Mon, 14 Mar 2011 22:02:36 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/?p=258</guid>
		<description><![CDATA[So, in response to Jamie Thomson&#8217;s article on extracting all SSIS packages from msdb, I also wanted to show how this can be done from within SSIS itself.  It&#8217;s very straightforward, and uses a data flow component you may not be familiar with: Export Column.

First, setup four package level variables:
FilePath &#8211; string
SSISFolderFilePath &#8211; string
SSISFolderName [...]]]></description>
			<content:encoded><![CDATA[<p>So, in response to Jamie Thomson&#8217;s <a href="http://sqlblog.com/blogs/jamie_thomson/archive/2011/02/02/export-all-ssis-packages-from-msdb-using-powershell.aspx">article</a> on extracting all SSIS packages from msdb, I also wanted to show how this can be done from within SSIS itself.  It&#8217;s very straightforward, and uses a data flow component you may not be familiar with: <a href="http://technet.microsoft.com/en-us/library/ms139818.aspx">Export Column</a>.</p>
<p><span id="more-258"></span></p>
<p>First, setup four package level variables:<br />
FilePath &#8211; string<br />
SSISFolderFilePath &#8211; string<br />
SSISFolderName &#8211; string<br />
SSISFolders &#8211; object</p>
<p><strong>FilePath</strong> should be set to the location where you want to store the packages.  Include the trailing slash, and ensure that the location exists.<br />
<strong>SSISFolderFilePath</strong> should be set to evaluate an expression (EvaluateAsExpression = TRUE), and its expression should be:<br />
@[User::FilePath] +  @[User::SSISFolderName]</p>
<p>Then create a connection manager object that points to your MSDB database where you want to extract from.  If you want this to be dynamic, perhaps to archive ALL SSIS packages in your company, then this could be made a dynamic connection manager object (by using expressions) and you iterate over each server.  For now, we&#8217;re only going to use one server.</p>
<p>Once these are setup, the rest is point and click, pretty much.  Add an Execute SQL Task to the control flow, and configure it so that it returns a full resultset.  See below.</p>
<p><img src="http://www.ssistalk.com/ssis_extractPackages001.png" alt="Execute SQL Task" /></p>
<p><img src="http://www.ssistalk.com/ssis_extractPackages002.png" alt="Execute SQL Task 2" /></p>
<p>The query for the Execute SQL Task is:<br />
<code>
<pre>
SELECT foldername
  FROM dbo.sysssispackagefolders folders
 WHERE EXISTS (SELECT NULL
                 FROM dbo.sysssispackages pkg
                WHERE pkg.folderid = folders.folderid)
</pre>
<p></code></p>
<p>*Note &#8211; the above SQL only assumes a flat directory structure.  If you have subdirectories in MSDB, you can use a recursive CTE to create a hierarchy resultset.</p>
<p>With the Execute SQL Task set up, you&#8217;ll have to <a href="http://consultingblogs.emc.com/jamiethomson/archive/2005/07/04/ssis-nugget_3a00_-execute-sql-task-into-an-object-variable-_2d00_-shred-it-with-a-foreach-loop.aspx">shred the results</a> using a Foreach Loop Container.  Inside the Foreach Loop Container, we will want to use a File System Task to create directories for our packages if they do not already exist.  The configuration for that is below:</p>
<p><img src="http://www.ssistalk.com/ssis_extractPackages003.png" alt="File System Task" /></p>
<p>Next, we have to create a data flow and attach it to the Foreach Loop Container.  The full control flow should resemble the next screenshot.</p>
<p><img src="http://www.ssistalk.com/ssis_extractPackages1.png" alt="Control Flow diagram" /></p>
<p>In the data flow, we have three components &#8211; OLE DB Source, Derived Column, and the Export Column transformation.  Connect the OLE DB source to your connection manager object, and use the following query against MSDB:<br />
<code>
<pre>
SELECT folder.foldername,
       pkg.name,
       pkg.packagedata
  FROM dbo.sysssispackages pkg
  JOIN dbo.sysssispackagefolders folder
    ON pkg.folderid = folder.folderid
</pre>
<p></code></p>
<p>Then, configure the Derived Column component so that it creates one new column, FullFilePath.  The following is the expression to use:<br />
<code>
<pre>
(DT_WSTR,500)(@[User::FilePath] + foldername + "\\" + name + ".dtsx")
</pre>
<p></code></p>
<p>Then configure the Export Column transformation as the following screenshot illustrates:</p>
<p><img src="http://www.ssistalk.com/ssis_extractPackages004.png" alt="Export Column configuration" /></p>
<p>The final data flow should look like the following:</p>
<p><img src="http://www.ssistalk.com/ssis_extractPackages005.png" alt="Data flow diagram" /></p>
<p>The only thing left to do is execute the package.  Navigate to the location defined by the FilePath package variable and you should see a directory structure resembling that in MSDB with all of the SSIS packages saved.</p>
<p><img src="http://www.ssistalk.com/ssis_extractPackages006.png" alt="File contents" /></p>
<p>If you wish to download the full SSIS package, here you go: <a href="http://www.ssistalk.com/ExportSSISPackages.dtsx">http://www.ssistalk.com/ExportSSISPackages.dtsx</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2011/03/14/ssis-export-all-ssis-packages-from-msdb/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Why is my data flow so slow with an OLE DB Command component?</title>
		<link>http://www.ssistalk.com/2009/10/29/ssis-why-is-my-data-flow-so-slow-with-an-ole-db-command-component/</link>
		<comments>http://www.ssistalk.com/2009/10/29/ssis-why-is-my-data-flow-so-slow-with-an-ole-db-command-component/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 17:04:07 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SSIS]]></category>
		<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/?p=182</guid>
		<description><![CDATA[&#8220;Why does my data flow take so long to execute when I use an OLE DB Command component?
&#8220;I need to update values in another table for every row in my data flow.&#8221;
These are common questions I see when dealing with &#8220;slow&#8221; performance of an SSIS package.  Sometimes though, the developer of the package does [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;Why does my data flow take so long to execute when I use an OLE DB Command component?<br />
&#8220;I need to update values in another table for every row in my data flow.&#8221;</p>
<p>These are common questions I see when dealing with &#8220;slow&#8221; performance of an SSIS package.  Sometimes though, the developer of the package does not even understand which component is taking so long to process say, thousands of records in their data flow, so it is understandable why this component may proliferate in many shops.  (Sometimes it is needed, of course, but you need to always ask the question &#8211; do I need the updates to happen RIGHT NOW?)</p>
<p>If you have a need to update data in another table, while still pushing data from a source to a destination, the OLE DB Command is often used because of the thought that it is part of the data flow, so why not use it.</p>
<p>Read on for more&#8230;.<br />
<span id="more-182"></span></p>
<p>The trouble with the OLE DB Command component is that it executes whatever command you have provided for each and every row that passes through it.  The data flow is designed to operate on buffers of data, which contain by default around 10,000 rows.  If you are simply moving data from one table to another, this concept works really well and quite fast too, I might add.</p>
<p>However, if you need to update data, should you use the OLE DB Command component in that data flow?  Are there other options?  The answers of course are &#8220;maybe&#8221; and &#8220;yes.&#8221;  </p>
<p>If you simply need to update data in a table and you don&#8217;t care when it happens, then I would recommend not using an OLE DB Command component at all in your data flow.  Instead, I recommend you build a staging table on your destination database server, and populate that table with your &#8220;update&#8221; data.  Then, in the control flow, after the data flow successfully executes, you can issue an Execute SQL Task to perform a batch update.</p>
<p>This recommendation is built on the fact that using an OLE DB Command component ensures that your update operations are done row-by-row, rather than in a batch operation.</p>
<p>Why?  How much faster is the batch operation compared to the OLE DB Command operation?  Well, the answer depends a bit, but in my simple test below, the time to update 5,000 records took 15 minutes using the OLE DB Command component and 4 seconds (yup &#8211; SECONDS) to populate a staging table and then perform a batch update.</p>
<p>Here is the setup I used:<br />
<code>
<pre>CREATE TABLE numbers (
  number int not null
)
GO

insert into numbers (number)
select number from
(
select row_number() over (order by s1.name) as number
  from sysobjects s1
 cross join sysobjects s2
 cross join sysobjects s3
 cross join sysobjects s4
 cross join sysobjects s5
) as numbers
where number between 1 and 1000000;
GO

select number
  from numbers
 where number < 5003;
GO

/*
number
1
2
3
4
5
...
4998
4999
5000
5001
5002
*/
</pre>
<p></code></p>
<p>Here is a picture of the first SSIS package. </p>
<p><a href="http://www.ssistalk.com/ole_db_command_1.png"><img alt="OLE DB Command Data Flow setup" src="http://www.ssistalk.com/ole_db_command_1.png" title="OLE DB Command Setup" width="299" height="218" /></a></p>
<p>I used the following SQL for the OLE DB Source component:<br />
<code>
<pre>SELECT number
  FROM numbers
 WHERE number < 5001
 ORDER BY number DESC
</pre>
<p></code></p>
<p>I used the following expression in the Derived Column component to create a new column, new_number:<br />
<code>
<pre>number + 1
</pre>
<p></code></p>
<p>I used the following SQL in the OLE DB Command component:<br />
<code>
<pre>update numbers
  set number = ?
 where number = ?
</pre>
<p></code></p>
<p>In the OLE DB Command "Column Mappings" tab, I mapped the incoming column, new_number, to the Param_0 parameter, and the incoming column, number, to the parameter, Param_1.</p>
<p>I then executed the package.  Time to execute: 15 minutes, 43 seconds.</p>
<p><a href="http://www.ssistalk.com/ole_db_command_2.png"><img alt="OLE DB Command Data Flow setup" src="http://www.ssistalk.com/ole_db_command_2.png" title="OLE DB Command Setup" /></a></p>
<p>Next I tried the batch update approach.  Use the same setup as above, except replace the OLE DB Command component with an OLE DB Destination, and push the two data flow columns to a staging table.</p>
<p>Here is the data flow layout:<br />
<a href="http://www.ssistalk.com/execute_sql_task_4.png"><img alt="OLE DB Command Data Flow setup" src="http://www.ssistalk.com/execute_sql_task_4.png" title="OLE DB Command Setup" /></a></p>
<p>Here is the staging table DDL:<br />
<code>
<pre>CREATE TABLE staging_numbers (
  orig_number int not null,
  new_number int not null
)
</pre>
<p></code></p>
<p>Map the data flow column, number, to the orig_number field in the staging table.  Map the data flow column, new_number, to the new_number field in the staging table, as shown below:<br />
<a href="http://www.ssistalk.com/execute_sql_task_3.png"><img alt="OLE DB Command Data Flow setup" src="http://www.ssistalk.com/execute_sql_task_3.png" title="OLE DB Command Setup" /></a></p>
<p>Then, in the control flow, hook up an Execute SQL Task to the new Data Flow task, so that the Execute SQL Task executes after the Data Flow, as shown below:<br />
<a href="http://www.ssistalk.com/execute_sql_task_2.png"><img alt="OLE DB Command Data Flow setup" src="http://www.ssistalk.com/execute_sql_task_2.png" title="OLE DB Command Setup" /></a></p>
<p>The Execute SQL Task SQL is below:<br />
<code>
<pre>update numbers
  set number = staging_numbers.new_number
from numbers, staging_numbers
where numbers.number = staging_numbers.orig_number
</pre>
<p></code></p>
<p>Upon executing the package, the execution time shrank to under five seconds:<br />
<a href="http://www.ssistalk.com/execute_sql_task_1.png"><img alt="OLE DB Command Data Flow setup" src="http://www.ssistalk.com/execute_sql_task_1.png" title="OLE DB Command Setup" /></a></p>
<p>So, the moral of this story is that whenever you think you need to use an OLE DB Command component, ask yourself, "Do I *really* need to use this component, or should I use a different approach?"</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2009/10/29/ssis-why-is-my-data-flow-so-slow-with-an-ole-db-command-component/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Avoiding the Sort Components</title>
		<link>http://www.ssistalk.com/2009/09/17/ssis-avoiding-the-sort-components/</link>
		<comments>http://www.ssistalk.com/2009/09/17/ssis-avoiding-the-sort-components/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 15:38:17 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/?p=170</guid>
		<description><![CDATA[When using a Merge or Merge Join component in a data flow, your incoming data is required to be sorted.  While it may be easy to drop a Sort component into your data flow, it may make more sense to perform the sort in your source query (if you are using a source such [...]]]></description>
			<content:encoded><![CDATA[<p>When using a Merge or Merge Join component in a data flow, your incoming data is required to be sorted.  While it may be easy to drop a Sort component into your data flow, it may make more sense to perform the sort in your source query (if you are using a source such as an OLE DB Source component).</p>
<p>If you decide to use an ORDER BY in your source and want to tell the SSIS Data Flow that your data is sorted, follow the below steps:</p>
<p><span id="more-170"></span></p>
<p>First, ensure that your data is being sorted with the ORDER BY clause.  Make note of which column(s) are in the sort and their positions.</p>
<p>Second, open the Advanced Editor for the OLE DB Source component by right-clicking on the OLE DB Source and selecting &#8220;Show Advanced Editor&#8230;&#8221;   </p>
<p>Then, click on the &#8220;Input and Output Properties&#8221; tab.  </p>
<p>Then highlight the &#8220;OLE DB Source Output Properties&#8221; branch and set the &#8220;IsSorted&#8221; property to True.</p>
<p><img src="http://www.ssistalk.com/OLE_DB_Source_IsSorted_1.png" alt="IsSorted = True" /></p>
<p>Next, expand the &#8220;OLE DB Source Output Properties&#8221; branch.  From here, select the first column under &#8220;Output Columns&#8221; that corresponds to the first column in your ORDER BY clause.  Set its &#8220;SortKeyPosition&#8221; property to the number 1.</p>
<p><img src="http://www.ssistalk.com/OLE_DB_Source_IsSorted_2.png" alt="SortKeyPosition" /></p>
<p>Repeat the last step for each column in your ORDER BY clause, advancing the SortKeyPosition by one each time.  (1,2,3,&#8230;)</p>
<p>That&#8217;s it.  Now the SSIS Data Flow will understand and acknowledge that the incoming data is sorted and will not require a Sort Component between the source and a Merge Join component, for instance.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2009/09/17/ssis-avoiding-the-sort-components/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Lookup Cache Modes &#8211; Full, Partial, None</title>
		<link>http://www.ssistalk.com/2009/09/04/ssis-lookup-cache-modes-full-partial-none/</link>
		<comments>http://www.ssistalk.com/2009/09/04/ssis-lookup-cache-modes-full-partial-none/#comments</comments>
		<pubDate>Fri, 04 Sep 2009 14:32:44 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SSIS]]></category>
		<category><![CDATA[SSIS Advanced Techniques]]></category>
		<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/?p=162</guid>
		<description><![CDATA[There are many, many resources out on the &#8216;Net regarding SSIS and the Lookup component and what each of its cache modes are and how to implement them in your own package.  This is going to be a technical post, for those of you interested in what each cache mode does behind the scenes.

For [...]]]></description>
			<content:encoded><![CDATA[<p>There are many, many resources out on the &#8216;Net regarding SSIS and the Lookup component and what each of its cache modes are and how to implement them in your own package.  This is going to be a technical post, for those of you interested in what each cache mode does behind the scenes.</p>
<p><span id="more-162"></span></p>
<p>For this post, use the following schema and data:<br />
<code>
<pre>
create table fact_sales
(id int identity(1,1),
 sales_rep_id int,
 sales_dollars decimal(18,2)
)

create table dim_sales_rep
( id int identity(1,1),
  first_name varchar(30),
  last_name varchar(50)
  )

insert into fact_sales (sales_rep_id, sales_dollars) values (1,120.99);
insert into fact_sales (sales_rep_id, sales_dollars) values (2,24.87);
insert into fact_sales (sales_rep_id, sales_dollars) values (3,98.11);
insert into fact_sales (sales_rep_id, sales_dollars) values (4,70.64);
insert into fact_sales (sales_rep_id, sales_dollars) values (4,114.19);
insert into fact_sales (sales_rep_id, sales_dollars) values (4,37.00);
insert into fact_sales (sales_rep_id, sales_dollars) values (5,401.50);

insert into dim_sales_rep (first_name, last_name) values ('John','Doe');
insert into dim_sales_rep (first_name, last_name) values ('Jane','Doe');
insert into dim_sales_rep (first_name, last_name) values ('Larry','White');
insert into dim_sales_rep (first_name, last_name) values ('Carrie','Green');
insert into dim_sales_rep (first_name, last_name) values ('Adam','Smith');
</pre>
<p></code></p>
<p><strong>FULL Cache Mode</strong><br />
First, it is always advisable to build a query for the lookup, instead of choosing a table in the Table/View drop-down.  The primary reason is so that you can limit the resultset to only the columns needed to perform the lookup as well as return any columns needed downstream, and to have the ability to add a WHERE clause if needed.</p>
<p>The full cache mode will run the specified query (or its own depending on how you assigned the lookup table) and attempt to cache all of the results.  It will execute this query very early on in the package execution to ensure that the first set of rows coming out of the source(s) are cached.  If SSIS runs out of memory on the machine though, the data flow will fail as the lookup component will not spool its memory overflow to disk.  Be cautious of this fact.  Once the data is cached, the lookup component will not go back to the database to retrieve its records, so long as the data flow is not restarted.  (In SQL Server 2008, you can now reuse lookup caches.)</p>
<p>Using SQL Profiler, you can see that only one database call is made:<br />
<code>
<pre>
declare @p1 int
set @p1=1
exec sp_prepare @p1 output,NULL,N'select sales_rep_id, sales_dollars
 from fact_sales',1
select @p1
go
exec sp_execute 1
go
SET NO_BROWSETABLE ON
go
declare @p1 int
set @p1=1
exec sp_prepare @p1 output,NULL,N'select id, first_name, last_name
from dim_sales_rep',1
select @p1
go
exec sp_execute 1
go
exec sp_unprepare 1
go
exec sp_unprepare 1
go
</pre>
<p></code></p>
<p><strong>PARTIAL Cache Mode</strong><br />
Partial cache mode will not execute a query immediately at package execution.  Instead, it will wait until its first input row arrives.  Once the row arrives, whatever lookup value (in this case, sales_rep_id) is being passed in, will get substituted for a parameter, and then SSIS will send the query to the database for retrieval.  At this point, all of the data returned will be cached for future lookups.  If a new sales_rep_id is encountered, then the query will have to be re-executed, and the new resultset will get added to the lookup cache.</p>
<p>In other words, in the above data, if my source is &#8220;select sales_rep_id, sales_dollars from fact_sales&#8221;, we should have five database calls made by the lookup component.  Even though for sales_rep_id = 4 we have three entries, in partial cache mode the first time we retrieve the lookup records for sales_rep_id = 4, the results will be cached, allowing future occurrences of sales_rep_id = 4 to be retrieved from cache.</p>
<p>This is illustrated in the SQL Profiler data:<br />
<code>
<pre>
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',1
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',2
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',3
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',4
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',5
go
exec sp_unprepare 1
go</pre>
<p></code><br />
In the above data, you can see at the end each sales_rep_id being passed in.  Note that we only have one line for sales_rep_id = 4.  That&#8217;s because the remaining two records were bounced against the lookup cache, avoiding a trip to the database.</p>
<p><strong>NO Cache Mode</strong><br />
Using the NO Cache Mode will essentially tell SSIS that you want each incoming row (from fact_sales in this case) to be bounced against the database.  Since we have seven fact_sales rows, we will see seven calls to the database &#8211; MOST of the time.  It is important to note that even though we are telling the lookup component to avoid caching rows, it will keep the last match in memory and use it for the next comparison.  If the next comparison&#8217;s key value matches the value still in memory, a database call is avoided, and the value is carried forward.  </p>
<p>In our example data above, if we sort by sales_rep_id, we will still only have five calls to the database because after we lookup our first value of sales_rep_id = 4, it will be reused for the subsequent lookups for sales_rep_id = 4.  If we sort our data by sales_dollars, we will have six database calls, because only two sales_rep_id = 4 records are together and hence the first lookup is only used once.</p>
<p>Here is a simple table illustrating each no cache example mentioned above:<br />
<code>
<pre>SALES_REP_ID, SALES_DOLLARS, LOOKUP DATABASE CALL Y or N
1       120.99    Y
2       24.87     Y
3       98.11     Y
4       70.64     Y
4       114.19    N
4       37.00     N
5       401.50    Y
</pre>
<p></code><br />
<code>
<pre>SALES_REP_ID, SALES_DOLLARS, LOOKUP DATABASE CALL Y or N
2      24.87      Y
4      37.00      Y
4      70.64      N
3      98.11      Y
4      114.19     Y
1      120.99     Y
5      401.50     Y
</pre>
<p></code></p>
<p>The SQL Profiler data for the second example above is here:<br />
<code>
<pre>exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',2
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',4
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',3
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',4
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',1
go
exec sp_executesql N'select * from (select id, first_name, last_name
from dim_sales_rep) [refTable]
where [refTable].[id] = @P1',N'@P1 int',5
go</pre>
<p></code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2009/09/04/ssis-lookup-cache-modes-full-partial-none/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
		<item>
		<title>ETL World Record &#8211; 1 terabyte loaded in 30 minutes</title>
		<link>http://www.ssistalk.com/2009/03/15/etl-world-record-1-terabyte-loaded-in-30-minutes/</link>
		<comments>http://www.ssistalk.com/2009/03/15/etl-world-record-1-terabyte-loaded-in-30-minutes/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 03:45:02 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SSIS]]></category>
		<category><![CDATA[SSIS Advanced Techniques]]></category>
		<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/?p=127</guid>
		<description><![CDATA[I know, this isn&#8217;t &#8220;breaking&#8221; news or anything, but what is new is the white paper detailing how Microsoft was able to achieve this record breaking speed using SSIS.  Check it out below as its a very interesting read, and it may help generate some new ideas for your implementations.
http://blogs.msdn.com/sqlperf/archive/2009/03/03/an-etl-world-record-revealed-finally.aspx
]]></description>
			<content:encoded><![CDATA[<p>I know, this isn&#8217;t &#8220;breaking&#8221; news or anything, but what is new is the white paper detailing how Microsoft was able to achieve this record breaking speed using SSIS.  Check it out below as its a very interesting read, and it may help generate some new ideas for your implementations.</p>
<p><a href="http://blogs.msdn.com/sqlperf/archive/2009/03/03/an-etl-world-record-revealed-finally.aspx">http://blogs.msdn.com/sqlperf/archive/2009/03/03/an-etl-world-record-revealed-finally.aspx</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2009/03/15/etl-world-record-1-terabyte-loaded-in-30-minutes/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Lookup component CaSE gotcha</title>
		<link>http://www.ssistalk.com/2007/12/19/ssis-lookup-component-case-gotcha/</link>
		<comments>http://www.ssistalk.com/2007/12/19/ssis-lookup-component-case-gotcha/#comments</comments>
		<pubDate>Wed, 19 Dec 2007 20:20:03 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/2007/12/19/ssis-lookup-component-case-gotcha/</guid>
		<description><![CDATA[So, one of the pain points in SSIS is that the Lookup Component performs CaSE sensitive matching, as well as retaining any trailing spaces that may be in the data.  So be forewarned that when using the lookup component, it may behoove you to use a derived column upstream to TRIM([SSISColumn]) your data to [...]]]></description>
			<content:encoded><![CDATA[<p>So, one of the pain points in SSIS is that the Lookup Component performs CaSE sensitive matching, as well as retaining any trailing spaces that may be in the data.  So be forewarned that when using the lookup component, it may behoove you to use a derived column upstream to TRIM([SSISColumn]) your data to get rid of any leading/trailing whitespaces and to perform the same (if needed) on the SQL Server side via an SQL statement &#8211; ltrim(rtrim(SQLServerColumn)).  Also, if you have differing CaSEs among the incoming data and the reference data, you may need to convert one or the other, or both to UPPER/lower case before performing the lookup.</p>
<p>If you&#8217;d at least like to see CaSE INsensitive searches, please visit <a href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=311209">my submission</a> and lets see if we can get this feature added to SSIS in SQL Server 2008.  </p>
<p>One workaround for you, should you want to use it, is to use the Fuzzy Lookup Component instead.  This has its own problems, as I&#8217;ve made mention to in the above feature request submission.</p>
<p>Edit: Jamie Thomson <a href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=126371&#038;wa=wsignin1.0">submitted an identical request</a> before me but I&#8217;ve made reference to that submission in mine.  The idea was to get it in SSIS 2008.  Never-the-less, <a href="http://blogs.conchango.com/jamiethomson/archive/2007/08/21/SSIS_3A00_-Big-improvements-to-Lookup-in-SQL-Server-2008.aspx">Michael Entin claims</a> this feature request has been dropped due to lack of time.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2007/12/19/ssis-lookup-component-case-gotcha/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Stored Procedures and the OLE DB Source</title>
		<link>http://www.ssistalk.com/2007/10/10/ssis-stored-procedures-and-the-ole-db-source/</link>
		<comments>http://www.ssistalk.com/2007/10/10/ssis-stored-procedures-and-the-ole-db-source/#comments</comments>
		<pubDate>Wed, 10 Oct 2007 20:30:32 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/2007/10/10/ssis-stored-procedures-and-the-ole-db-source/</guid>
		<description><![CDATA[Many users have issues when trying to use a stored procedure in an OLE DB Source component.  Here are some tips:

Ensure that there is a final select statement at the end of the stored procedure to ensure the correct resultset is returned
At the top of the stored procedure as part of the procedure code, [...]]]></description>
			<content:encoded><![CDATA[<p>Many users have issues when trying to use a stored procedure in an OLE DB Source component.  Here are some tips:</p>
<ul>
<li>Ensure that there is a final select statement at the end of the stored procedure to ensure the correct resultset is returned</li>
<li>At the top of the stored procedure as part of the procedure code, add the following line: SET NOCOUNT ON</li>
<li>At the top of the OLE DB Source SQL statement and before you issue the EXEC YourSproc line, add the following: SET FMTONLY OFF.</li>
</ul>
<p>This should ensure that when you click on the column mapping tab, the columns are correctly displayed.</p>
<p>Also another approach is to use a table variable in the stored proc.  Then at the end, select from that table variable.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2007/10/10/ssis-stored-procedures-and-the-ole-db-source/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Lookup component improvements?</title>
		<link>http://www.ssistalk.com/2007/08/22/ssis-lookup-component-improvements/</link>
		<comments>http://www.ssistalk.com/2007/08/22/ssis-lookup-component-improvements/#comments</comments>
		<pubDate>Wed, 22 Aug 2007 13:45:51 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/2007/08/22/ssis-lookup-component-improvements/</guid>
		<description><![CDATA[Jamie Thomson has posted four SSIS lookup component feature requests that have been recently closed as &#8220;fixed&#8221; by Microsoft.  Hopefully these will make it into the next CTP of SQL Server 2008.  Take a look because they all have very high potentials to increase your productivity and useability of SSIS.
See them here: http://blogs.conchango.com/jamiethomson/archive/2007/08/21/SSIS_3A00_-Big-improvements-to-Lookup-in-SQL-Server-2008.aspx
]]></description>
			<content:encoded><![CDATA[<p>Jamie Thomson has posted four SSIS lookup component feature requests that have been recently closed as &#8220;fixed&#8221; by Microsoft.  Hopefully these will make it into the next CTP of SQL Server 2008.  Take a look because they all have very high potentials to increase your productivity and useability of SSIS.</p>
<p>See them here: <a href="http://blogs.conchango.com/jamiethomson/archive/2007/08/21/SSIS_3A00_-Big-improvements-to-Lookup-in-SQL-Server-2008.aspx" title="SSIS Junkie: Big Improvements with lookup component" target="_blank">http://blogs.conchango.com/jamiethomson/archive/2007/08/21/SSIS_3A00_-Big-improvements-to-Lookup-in-SQL-Server-2008.aspx</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2007/08/22/ssis-lookup-component-improvements/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Using a Script Component as a Source</title>
		<link>http://www.ssistalk.com/2007/04/04/ssis-using-a-script-component-as-a-source/</link>
		<comments>http://www.ssistalk.com/2007/04/04/ssis-using-a-script-component-as-a-source/#comments</comments>
		<pubDate>Wed, 04 Apr 2007 15:09:39 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SQL Server 2005]]></category>
		<category><![CDATA[SQL Server 2008]]></category>
		<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/2007/04/04/ssis-using-a-script-component-as-a-source/</guid>
		<description><![CDATA[Just a quick tutorial on using a script component as a source&#8230;  Follow the link for screenshots.

First things first.  Add a script component to the data flow.  When prompted, select &#8220;Source&#8221; as the component type.  (click on images for full sized version)

Next, for clarity&#8217;s sake, I&#8217;ll rename the default output.  [...]]]></description>
			<content:encoded><![CDATA[<p>Just a quick tutorial on using a script component as a source&#8230;  Follow the link for screenshots.</p>
<p><span id="more-42"></span></p>
<p>First things first.  Add a script component to the data flow.  When prompted, select &#8220;Source&#8221; as the component type.  (click on images for full sized version)</p>
<p><a href="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source.jpg" title="SSIS - Script Source Component 1"><img src="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source.jpg" alt="SSIS - Script Source Component 1" height="282" width="434" /></a></p>
<p>Next, for clarity&#8217;s sake, I&#8217;ll rename the default output.  (An output simply contains a set of columns and will correlate to the green arrow on the data flow.  The more outputs you have, the more green arrows you can use.)  I&#8217;ll rename the default output, &#8220;Output 0&#8243; to &#8220;MyOutput.&#8221;</p>
<p><a href="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source2.jpg" title="SSIS - Script Source Component 2"><img src="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source2.jpg" alt="SSIS - Script Source Component 2" height="430" width="440" /></a></p>
<p>Next, I&#8217;ll add an output column called, &#8220;MyColumn&#8221; and its type will be an integer.  Be sure to change the type accordingly.</p>
<p><a href="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source3.jpg" title="SSIS - Script Source Component 3"><img src="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source3.jpg" alt="SSIS - Script Source Component 3" height="434" width="444" /></a></p>
<p>From here, we can edit the script by clicking on the script section on the left of the above window.  From there click on the &#8220;Design Script&#8230;&#8221; button.  Below is the setup:</p>
<p><a href="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source4.jpg" title="SSIS - Script Source Component 4"><img src="http://www.ssistalk.com/wp-content/uploads/2007/04/ssis_script_as_source4.jpg" alt="SSIS - Script Source Component 4" /></a></p>
<p>Notice how when I type, I am automatically prompted for a list of available items to choose from.  One of them is the column I added previously.  Let&#8217;s pick the column and assign a value of 123 to it.  Full script below:</p>
<p>For SSIS 2005:</p>
<p><code>
<pre>Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

Public Class ScriptMain
    Inherits UserComponent

    Public Overrides Sub CreateNewOutputRows()
        MyOutputBuffer.AddRow()
        MyOutputBuffer.MyColumn = 123
    End Sub

End Class</pre>
<p></code></p>
<p>For SSIS 2008, it&#8217;s a bit different:<br />
Visual Basic:<br />
<code>
<pre>
Imports System
Imports System.Data
Imports System.Math
Imports Microsoft.SqlServer.Dts.Pipeline.Wrapper
Imports Microsoft.SqlServer.Dts.Runtime.Wrapper

&lt;Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute&gt; _
&lt;CLSCompliant(False)&gt; _
Public Class ScriptMain
    Inherits UserComponent

    Public Overrides Sub CreateNewOutputRows()
        Output0Buffer.AddRow()
        Output0Buffer.Column = 123
    End Sub

End Class
</pre>
<p></code></p>
<p>C#:<br />
<code>
<pre>
using System;
using System.Data;
using Microsoft.SqlServer.Dts.Pipeline.Wrapper;
using Microsoft.SqlServer.Dts.Runtime.Wrapper;

[Microsoft.SqlServer.Dts.Pipeline.SSISScriptComponentEntryPointAttribute]
public class ScriptMain : UserComponent
{

  public override void CreateNewOutputRows()
    {
        Output0Buffer.AddRow();
        Output0Buffer.Column = 123;
    }

}
</pre>
<p></CODE></p>
<p>You can close the script and then click OK on the script component dialog box.  Now when you hook this source up to another component, you'll end up with one column with one row with a value of 123.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2007/04/04/ssis-using-a-script-component-as-a-source/feed/</wfw:commentRss>
		<slash:comments>39</slash:comments>
		</item>
		<item>
		<title>SSIS &#8211; Working with cobol zoned (signed) decimals</title>
		<link>http://www.ssistalk.com/2007/03/14/ssis-working-with-cobol-zoned-signed-decimals/</link>
		<comments>http://www.ssistalk.com/2007/03/14/ssis-working-with-cobol-zoned-signed-decimals/#comments</comments>
		<pubDate>Wed, 14 Mar 2007 20:43:00 +0000</pubDate>
		<dc:creator>Phil Brammer</dc:creator>
				<category><![CDATA[SSIS Data flow]]></category>

		<guid isPermaLink="false">http://www.ssistalk.com/2007/03/14/ssis-working-with-cobol-zoned-signed-decimals/</guid>
		<description><![CDATA[Over on the forums today a user, Pra Rav, has asked how do we work with mainframe zoned decimals.  I have the answer, at least on how *I* deal with them.  Take it or leave it as there may be other ways to do this, but it works slick enough for me to [...]]]></description>
			<content:encoded><![CDATA[<p>Over on the forums today a user, Pra Rav, has asked how do we work with mainframe zoned decimals.  I have the answer, at least on how *I* deal with them.  Take it or leave it as there may be other ways to do this, but it works slick enough for me to blog about it and to share it with Pra.  Read on&#8230;.</p>
<p><span id="more-35"></span></p>
<p>Let&#8217;s say we have the following data file with two rows in it.  This data file contains three columns:</p>
<p><code>06   000960{   00000{<br />
07   000471C   00074}</code></p>
<p>What do we have here?  The first column represents a key, perhaps.  The second and third columns could be dollar amounts, perhaps.  In normal terms the fields above are really representing:</p>
<p><code>06    +9600    +00<br />
07    +4713    -740</code></p>
<p>The problem with zoned decimals, and it&#8217;s not really a big deal, is that the last byte is overlaid with a sign representation.  The last byte indicates the sign AND the numerical value.  One other thing to note is that the data does not contain decimal point placement information.  That is handled outside of the storage and is really a presentation layer feature.</p>
<p>So, how do we work with this in SSIS?  Actually, it&#8217;s pretty easy with some simple tricks.  (I&#8217;m going to move away from the file processing and just pretend that I only have one field containing a zoned decimal called &#8220;CurrencyValue.&#8221;)</p>
<p>Basically we only need three transformations in the data flow to convert these values: two derived columns and a lookup transformation.</p>
<p><img src="http://www.ssistalk.com/wp-content/uploads/2007/03/zoned02.JPG" alt="Zoned Decimals 01" /></p>
<p>In the first derived column transformation, we do two things.  The first is to grab the right-most character of our field.  This character contains the sign for the entire number and the numerical value of the last digit.  We also check to ensure that we don&#8217;t have nulls or blanks coming in, if we do, assign a default value of &#8220;0{&#8221; just to passify the later transformations.</p>
<p><a href="http://www.ssistalk.com/wp-content/uploads/2007/03/zoned01.JPG" title="Zoned Decimals 02"><img src="http://www.ssistalk.com/wp-content/uploads/2007/03/zoned01.JPG" alt="Zoned Decimals 02" height="350" width="483" /></a></p>
<p>As you can see above (click on the image to expand it), we added a column &#8220;SignChar&#8221; and replaced the CurrencyValue column with a default value if nothing existed there.  Pretty simple and straightforward stuff.</p>
<p>Next, we add a simple lookup table.  This &#8220;table&#8221; is really just an SQL statement to perform our conversion. We&#8217;ll output the sign and the numerical value from this lookup.  Use the SQL below to build the lookup table:</p>
<p><code>select 1 as sign, '{' as lookupvalue, 0 as returnvalue<br />
union all<br />
select 1 as sign, 'A' as lookupvalue, 1 as returnvalue<br />
union all<br />
select 1 as sign, 'B' as lookupvalue, 2 as returnvalue<br />
union all<br />
select 1 as sign, 'C' as lookupvalue, 3 as returnvalue<br />
union all<br />
select 1 as sign, 'D' as lookupvalue, 4 as returnvalue<br />
union all<br />
select 1 as sign, 'E' as lookupvalue, 5 as returnvalue<br />
union all<br />
select 1 as sign, 'F' as lookupvalue, 6 as returnvalue<br />
union all<br />
select 1 as sign, 'G' as lookupvalue, 7 as returnvalue<br />
union all<br />
select 1 as sign, 'H' as lookupvalue, 8 as returnvalue<br />
union all<br />
select 1 as sign, 'I' as lookupvalue, 9 as returnvalue<br />
union all<br />
select -1 as sign, '}' as lookupvalue, 0 as returnvalue<br />
union all<br />
select -1 as sign, 'J' as lookupvalue, 1 as returnvalue<br />
union all<br />
select -1 as sign, 'K' as lookupvalue, 2 as returnvalue<br />
union all<br />
select -1 as sign, 'L' as lookupvalue, 3 as returnvalue<br />
union all<br />
select -1 as sign, 'M' as lookupvalue, 4 as returnvalue<br />
union all<br />
select -1 as sign, 'N' as lookupvalue, 5 as returnvalue<br />
union all<br />
select -1 as sign, 'O' as lookupvalue, 6 as returnvalue<br />
union all<br />
select -1 as sign, 'P' as lookupvalue, 7 as returnvalue<br />
union all<br />
select -1 as sign, 'Q' as lookupvalue, 8 as returnvalue<br />
union all<br />
select -1 as sign, 'R' as lookupvalue, 9 as returnvalue</code></p>
<p>Next, set up the mappings:</p>
<p><a href="http://www.ssistalk.com/wp-content/uploads/2007/03/zoned03.JPG" title="Zoned Decimals 03"><img src="http://www.ssistalk.com/wp-content/uploads/2007/03/zoned03.JPG" alt="Zoned Decimals 03" height="562" width="514" /></a></p>
<p>We map our input, SignChar to &#8220;lookupvalue&#8221; and return &#8220;returnvalue&#8221; and &#8220;sign.&#8221;</p>
<p>The last step is to calculate the actual value of the zoned decimal.  We use the second derived column to do this and basically we replace the last character of the zoned decimal with &#8220;returnvalue&#8221; and then multiply that value by &#8220;sign.&#8221;</p>
<p>(In my work I chose to have the output of this be character data, but you could cast it to a decimal, integer, whatever if you desire.)</p>
<p><a href="http://www.ssistalk.com/wp-content/uploads/2007/03/zoned04.JPG" title="Zoned Decimals 04"><img src="http://www.ssistalk.com/wp-content/uploads/2007/03/zoned04.JPG" alt="Zoned Decimals 04" height="482" width="514" /></a></p>
<p>Here&#8217;s the expression:</p>
<p><code>(DT_STR,17,1252)(sign * (DT_I8)REPLACE(CurrencyValue, RIGHT(CurrencyValue,1), (DT_WSTR,1)returnvalue))</code></p>
<p>And that&#8217;s pretty much it.  NewCurrencyValue will contain the converted number from Zoned Decimal to a &#8220;normal&#8221; representation to be able to be used in calculations and such.</p>
<p><strong>NOTE: There is one gotcha with this.</strong>  The example I provided above works well for ONE column.  If you have many, you&#8217;d better look into unpivoting the records first before going into the first derived column transformation, and then pivot them back when done with the last derived column.  That way, you only have to build this once, versus one for each column.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.ssistalk.com/2007/03/14/ssis-working-with-cobol-zoned-signed-decimals/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>

