Using a temporary table in SSIS, especially in a Data Flow Task, could be challenging. SSIS tries to validate tables and their column metadata at design time. As the Temp table does not exist at the design time, SSIS cannot validate its metadata and throws an error. I will present a pretty straight forward solution here to trick SSIS into believing that the Temp table actually exists and proceed as normal.
Temporary Table Reference Across Two Tasks
To begin with, I will demonstrate that a Temp table can be referenced across two tasks. Add two Execute SQL Tasks in your package. Both of them use the same OLEDB connection. The first task creates a Local Temp table and inserts one row into it. The second task tries to insert one more row in the same table.
TSQL script in the first task –
/* Create a LOCAL temp table*/ IF ( Object_id('[tempdb].[dbo].[#LocalTable]') IS NOT NULL ) DROP TABLE [tempdb].[dbo].[#LocalTable] GO CREATE TABLE [#LocalTable] ( id INT IDENTITY, label VARCHAR(128) ); GO /* Insert one row */ INSERT INTO [#LocalTable] (label) VALUES ('First row'); GO
TSQL script in the second task –
/* Insert one row */ INSERT INTO [#LocalTable] (label) VALUES ('Second row'); GO
Invalid Object Name Error
When executed, the SSIS package gives the following error because the second task cannot see the Temp table created in the first task. Local Temp tables are specific to a connection. When SSIS switches from one task to another, it resets the connection so the Local Temp table is also dropped.
Error: 0xC002F210 at ESQLT-InsertSecondRow , Execute SQL Task: Executing the query "/* Insert second row */ INSERT INTO [#LocalTable]..." failed with the following error: "Invalid object name '#LocalTable'.". Possible failure reasons: Problems with the query , "ResultSet" property not set correctly , parameters not set correctly , or connection not established correctly. Task failed: ESQLT-InsertSecondRow Warning: 0x80019002 at SSIS-DemoTempTable: SSIS Warning Code DTS_W_MAXIMUMERRORCOUNTREACHED. The Execution method succeeded, but the number of errors raised (1) reached the maximum allowed (1); resulting in failure. This occurs when the number of errors reaches the number specified in MaximumErrorCount. Change the MaximumErrorCount or fix the errors. SSIS package "SSIS-DemoTempTable.dtsx" finished: Failure.
The fix is pretty simple. Right-click on the OLEDB connection manager and go to the Properties window. Change the RetainSameConnection property to True. This will force the connection manager to keep the same connection open. I have another post with more details about the RetainSameConnection property of OLEDB connection managers.
This fixes the error and the package executes successfully.
Temporary Table in a Data Flow Task
Now let me demonstrate that a Temp table can be used in a Data Flow Task.
Add a Data Flow Task to the package.
In the Data Flow task, add an OLEDB source that will use the same OLEDB connection as used by the Execute SQL Tasks earlier. In the OLEDB Source Editor window, there is no way to find our Local Temp table in the list so close the Editor window.
The Development Workaround
Open a SSMS query window and connect to the SQL Server used in the OLEDB connection. Now create a Global Temp table with the same column definition. You can just copy the CREATE TABLE script and add one more # symbol to the table name.
The Global Temp table is just a development workaround for the restriction imposed by the volatility of the Local Temp table. You can even use an actual physical table instead of the Global Temp table. We will switch to the Local Temp table in the end of this post and then the Global Temp table (or the actual physical table) can be dropped.
/* Create a GLOBAL temp table with the same schema as the earlier LOCAL temp table. Note the ## in the table name */ CREATE TABLE [##LocalTable] ( id INT IDENTITY, label VARCHAR(128) ); GO
Come back to the SSIS Control Flow. Create a new package scoped variable of String data type. Give it the name TableName and put the Global Temp table name as its value.
Go to the Data Flow > OLEDB Source and double click to open the OLEDB Source Editor window. Choose the Data Access Mode as Table name or view name variable. In the Variable name drop-down, choose the new variable that we created. This means that now the OLEDB Source is going to use the GLOBAL Temp table. Of course, it is not the same as the LOCAL Temp table but we will get to that in a minute. Click on the Columns tab to load the table metadata. Then click on OK to close the OLEDB Source Editor.
Now add a Flat File Destination and configure its properties. I’ll not go into those details. Please let me know in the comments or via email if you need information on how to configure a Flat File Destination.
The final Data Flow Task looks like this.
You can execute the package now to verify if it runs successfully. Although it will run fine, the flat file will not have rows because the source of the data is the Global Temp table, not the Local Temp table populated by the Execute SQL Tasks.
A Global Temp table (or a physical table) is common to all users so it could cause issues in multi-user environments. Local Temp tables are specific to a connection, hence more scalable. All that is needed now is to remove one # in the variable value and the OLEDB Source will point to the correct Local Temp table. To clean up, you can drop the Global Temp table.
The flat file will have the rows inserted by the Execute SQL Tasks.
Subsequent runs of the package will show validation errors because the Local Temp table is not available when the package starts. To go around this, you can set the DelayValidation property of the package to TRUE. As the package is the parent container for all other tasks, this property will be applied to all tasks in the package. If you do not wish to disable validation for all tasks, then you can set it for individual tasks, i.e. the first Execute SQL Task and the Data Flow Task. Again, the Data Flow Task may contain multiple sources, destinations and transformations and you may not want to disable validation for all of them. In that case you can be more granular and set just the ValidateExternalMetadata property of the OLEDB Source to FALSE.