3

Background

I would like to load data for 8 tables from Source (This gets data from some other place) to Target. I have a control table in my source that maintains entries every time a table is loaded. So before I start my SSIS package, I need to check if the control table in source has entries for all 8 tables.

SSIS Package Structure

  1. Two variables RecordCount (default 0) & SQLQueryForRecordCount (SQL Query to get record count from control table)
  2. Execute SQL Task - Here I am executing the select query to get record count and passing the result to variable RecordCount
  3. While connecting data flow with execute sql script, I have selected Expression as Evaluation Operation and expression as @[User::RecordCount] == 8 so that Data Flow will be executed when the RecordCount = 8.

Everything works fine till now.

The Problem is we are not sure about when the entries will be inserted into control table in source (it can be done anytime in a 3 hours window). So I would like to loop the 2nd step (execute sql script) until the RecordCount variable value reaches 8 and then kick off next data flow tasks.

How to achieve this? Please help me.

Hadi
  • 36,233
  • 13
  • 65
  • 124
Venkat N
  • 31
  • 3
  • If there is a 3 hours window time, why you don't set the package execution time to execute at the end of the 3 hours? – TheEsnSiavashi May 25 '17 at 20:23
  • 1
    @TheEsisia Generally this situation comes up when there is a window to *begin* processing, but you still want to start as soon as possible... – Aaron Dietz May 25 '17 at 20:26
  • Yes Aaron, you are right. Even though there is 3 hour window, we would like to start data load into next system as soon as possible. – Venkat N May 25 '17 at 20:32

2 Answers2

3

I find it easier to do this within a stored procedure, and also prefer the ability to adjust it without editing/deploying/promoting my packages.

In SSIS, you will want a simple execute SQL task that calls the stored procedure. Then for the stored procedure, you would want something like:

DECLARE @CountProcessed int

SELECT @CountProcessed = SUM(ControlField)
FROM ControlTable

WHILE @CountProcessed <> 8
   BEGIN
     WAITFOR DELAY 00:01:00 --Set to whatever time increment you want to wait
     SELECT @CountProcessed = SUM(ControlField)
     FROM ControlTable
   END

You can then discard your SSIS variables, and simply start with this proc. No constraints needed.

Aaron Dietz
  • 10,137
  • 1
  • 14
  • 26
  • Hi Aaron, Thank you very much for the reply. This looks like a good solution. Is there any way that we can achieve this inside SSIS package with out using Procedure. – Venkat N May 25 '17 at 20:29
  • @VenkatN You certainly can (although I still highly recommend against it for the visibility reasons I mentioned). Your next best choice is to put the above into an execute script task, instead of building a procedure and calling it. It will function the same way, but the code will live inside that task instead of in your database. – Aaron Dietz May 25 '17 at 20:42
2

Script Task workaround

You can do a workaround using a Script Task instead of Execute SQL Task:

  1. Inside the Script Task use a SQLCommand to retrieve the RecordCount
  2. Add a While Loop that will repeat the SqlCommand execution until the RecordCount = 8
  3. Your code should look like:

    Dim recordcount As Integer = 0
    Dim sqlQuery As String = ""
    Public Sub Main()
    
        sqlQuery = Dts.Variables.Item("User::SQLQueryForRecordCount ").Value.ToString
    
        Using sqlcon As New SqlClient.SqlConnection("Server=myServerName\myInstanceName;Database=myDataBase;Integrated Security=SSPI;")
    
            sqlcon.Open()
    
    
    
            While recordcount < 8
    
                Using sqlcmd As New SqlClient.SqlCommand(sqlQuery, sqlcon)
    
    
                    recordcount = CInt(sqlcmd.ExecuteScalar())
                    'Theading.Thread.Sleep(5000) wait for 5 seconds
    
                End Using
    
    
    
            End While
    
    
        End Using
    
        Dts.Variables.Item("User::RecordCount").Value = recordcount
    
        Dts.TaskResult = ScriptResults.Success
    End Sub
    
  4. At the end assign the Count Value to the recordCount Variable

Note: that you must add User::RecordCount as ReadWriteVariable and User::SQLQueryForRecordCount as ReadOnly Variable in the Script editor

Side Note: you can add a Theading.Thread.Sleep(5000) command inside the While loop to give more time for each command execution

Hadi
  • 36,233
  • 13
  • 65
  • 124
  • Hi Hadi, Thank you very much for the reply. How can I state 'Windows Authentication' instead of password in SqlConnection. Sorry if I am asking basic questions. This is my first VB script in my career. – Venkat N May 25 '17 at 21:33
  • I have created VB script and following image has the details: [Script](https://prnt.sc/fc5a6m). I am getting following error when I run package [Error](https://prnt.sc/fc5apb). Please help me. – Venkat N May 25 '17 at 22:46
  • @VenkatN in the connection string you provided a server name without instance it should look like `myServerName\myInstanceName` – Hadi May 25 '17 at 22:49
  • Our server doesn't have instance name. What should we provide if instance name is blank. – Venkat N May 25 '17 at 23:07
  • Server name is the machine name, instance is the sql server instance. You can get it from the oledb connection used in the execute sql task – Hadi May 25 '17 at 23:31
  • I have added instance name to the script. this is the updated [Script](https://prnt.sc/fc62d6). Still it is giving same [Error](https://prnt.sc/fc62qm). – Venkat N May 26 '17 at 00:24
  • The code is fine. But the exception is unclear. Try adding a breakpoint on the first line of code and debug the code – Hadi May 26 '17 at 07:00
  • https://stackoverflow.com/questions/28997381/runtime-error-exception-has-been-thrown-by-the-target-of-an-invocation-from-sc – Hadi May 26 '17 at 07:11