{"id":2182,"date":"2014-02-19T09:56:52","date_gmt":"2014-02-19T09:56:52","guid":{"rendered":"http:\/\/bicortex.com\/?p=2182"},"modified":"2014-02-19T10:27:17","modified_gmt":"2014-02-19T10:27:17","slug":"sql-server-data-synchronization-automation-using-tablediff-utility-and-ssis-part-2","status":"publish","type":"post","link":"http:\/\/bicortex.com\/bicortex\/sql-server-data-synchronization-automation-using-tablediff-utility-and-ssis-part-2\/","title":{"rendered":"SQL Server Data Synchronization Automation Using Tablediff Utility and SSIS &#8211; Part 2"},"content":{"rendered":"<p style=\"text-align: justify;\">In the <a href=\"http:\/\/bicortex.com\/sql-server-data-synchronization-automation-using-tablediff-utility-and-ssis-part-1\/\" target=\"_blank\"><b>FIRST<\/b><\/a> post this short series I briefly outlined tablediff utility and set the stage (databases, objects, directories and batch file) for the SSIS package responsible for data synchronization workflow. In this post I will continue with the solution development and show you how to build and configure the package to take advantage of the tablediff tool and merge data across the 2 databases and their objects deployed as per <a href=\"http:\/\/bicortex.com\/sql-server-data-synchronization-automation-using-tablediff-utility-and-ssis-part-1\/\" target=\"_blank\"><b>PART 1 <\/b><\/a>prelude. The complete package can be downloaded from my SkyDrive folder <a href=\"https:\/\/skydrive.live.com\/redir?resid=715AEF07A82832E1!57856&amp;authkey=!ABfhXRxFGwnYZgY&amp;ithint=folder%2c.bat\" target=\"_blank\"><b>HERE<\/b><\/a> if you wish to use it as a template &#8211; just make sure you adjust all necessary parameters e.g. database connection details etc. to correspond to your environment. I have also attached a short video footage depicting the package execution and the outcome on the tables\u2019 data synchronization and SQL files management at the end of this post.<\/p>\n<p style=\"text-align: justify;\">The complete package looks as per image below, with the core functionality encapsulated in the first two sections. The remaining Script Task and the second ForEach Loop Container are there to provide additional features i.e. the Script Task checking whether the file(s) have been created in the nominated directories and the second ForEach Loop Container to execute scripts generated by the tablediff utility and archive the files processed into a separate directory.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_complete_SSIS_package.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2183\" alt=\"Tablediff_complete_SSIS_package\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_complete_SSIS_package.png\" width=\"580\" height=\"130\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Let\u2019s start with creating a bunch of variables which will house the data temporarily used during package runtime or provide value-dependant execution topology. Most of the variables are pretty self-explanatory with names reflecting their function. Common_Var variable of the System.Object type will house the results of the query against the Params_details table (see previous post <a href=\"http:\/\/bicortex.com\/sql-server-data-synchronization-automation-using-tablediff-utility-and-ssis-part-1\/\" target=\"_blank\"><b>HERE<\/b><\/a>) whereas the Boolean File_Exists variable is populated by the Script Task and its value determines execution pathway depending on whether the file(s) have been created or not. Finally, Temp_FileName is used by the second ForEach Loop Container in iterating through SQL files created.<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_variables_collection.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2185\" alt=\"Tablediff_SSIS_variables_collection\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_variables_collection.png\" width=\"580\" height=\"282\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_variables_collection.png 580w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_variables_collection-300x145.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Looking at the Connection Manager, there is one database connection pointing to the Source_DB database and 2 file connections \u2013 Archived_Files which points to the archive directory (C:\\Diffoutput\\Archived_Files) and Temp_FileName one which is using an expression for connection string as per image below.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_Temp_Filename_conn_expression.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2189\" alt=\"Tablediff_Temp_Filename_conn_expression\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_Temp_Filename_conn_expression.png\" width=\"580\" height=\"90\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Let\u2019s go through the Control Flow pane now and outline the individual containers roles. Starting with Execute SQL Task 1 transformation, it simply executes the SELECT SQL statement, returning the data as a full results set, which in turn is mapped to the Common_Var variable as per below.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_Exec_SQL1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2190\" alt=\"Tablediff_SSIS_Exec_SQL1\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_Exec_SQL1.png\" width=\"580\" height=\"360\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_Exec_SQL1_Var_Assignment.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2191\" alt=\"Tablediff_SSIS_Exec_SQL1_Var_Assignment\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_Exec_SQL1_Var_Assignment.png\" width=\"580\" height=\"93\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_Exec_SQL1_Var_Assignment.png 580w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_Exec_SQL1_Var_Assignment-300x48.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Next, the first ForEach Loop Container is configured to use the ADO object source variable Common_Var and the following variables mappings.<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_ForEach_Loop1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2192\" alt=\"Tablediff_SSIS_ForEach_Loop1\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_ForEach_Loop1.png\" width=\"580\" height=\"351\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_ForEach_Loop1.png 580w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_ForEach_Loop1-300x181.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_ForEach_Loop1_Var_Mapping.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2193\" alt=\"Tablediff_SSIS_ForEach_Loop1_Var_Mapping\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_ForEach_Loop1_Var_Mapping.png\" width=\"580\" height=\"213\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_ForEach_Loop1_Var_Mapping.png 580w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_ForEach_Loop1_Var_Mapping-300x110.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Note that the column order used in the SELECT SQL statement from the first transformation is corresponding to the variables assignment in the first ForEach Loop Container, otherwise the package will fail.<\/p>\n<p style=\"text-align: justify;\">Execute Process Task simply runs the batch file saved in the nominated directory, passing the variables as arguments in a form of an expression as per below. Also, note that the order in which those appear in the expression corresponds to the SELECT SQL statement attributes order and variable mapping in the ForEach Loop Container order.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_exec_process_process_property.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2194\" alt=\"Tablediff_exec_process_process_property\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_exec_process_process_property.png\" width=\"580\" height=\"255\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_exec_process_process_property.png 606w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_exec_process_process_property-300x131.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_exec_process_expression_property.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2195\" alt=\"Tablediff_exec_process_expression_property\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_exec_process_expression_property.png\" width=\"580\" height=\"400\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Notice that the FailTaskIfReturnCodeIsNotSuccessValue property is set to False. This is due to the fact that if no changes are detected, the tablediff will return SucessValue of 1 which effectively fails package execution. As we don\u2019t want to treat this as an error or exception FailTaskIfReturnCodeIsNotSuccessValue property needs to be changed from its default setting to False value.<\/p>\n<p style=\"text-align: justify;\">Following on, we have a Script Component with a very simply VB.NET code snippet checking for SQL files existence. I know in the first post I said that no code will be required but this section is not compulsory, uses default SSIS functionality and is only there as an enhancement so you can remove it if you wish. The File_Exists variable is also listed in the ReadOnlyVariables property.<\/p>\n<p style=\"text-align: justify;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_script_task_config.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2198\" alt=\"Tablediff_SSIS_script_task_config\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_script_task_config.png\" width=\"580\" height=\"120\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_script_task_config.png 580w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_script_task_config-300x62.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<pre class=\"brush: sql; title: ; notranslate\" title=\"\">\r\n#Region &quot;Imports&quot;\r\nImports System\r\nImports System.Data\r\nImports System.Math\r\nImports Microsoft.SqlServer.Dts.Runtime\r\nImports System.IO\r\n#End Region\r\n\r\n&lt;Microsoft.SqlServer.Dts.Tasks.ScriptTask.SSISScriptTaskEntryPointAttribute()&gt; _\r\n&lt;System.CLSCompliantAttribute(False)&gt; _\r\nPartial Public Class ScriptMain\r\n    Inherits Microsoft.SqlServer.Dts.Tasks.ScriptTask.VSTARTScriptObjectModelBase\r\n\r\n    Public Sub Main()\r\n        Dim directory As DirectoryInfo = New DirectoryInfo(&quot;c:\\DiffOutput&quot;)\r\n        Dim file As FileInfo() = directory.GetFiles(&quot;*.sql&quot;)\r\n\r\n        If file.Length &gt; 0 Then\r\n            Dts.Variables(&quot;User::File_Exists&quot;).Value = True\r\n        Else\r\n            Dts.Variables(&quot;User::File_Exists&quot;).Value = False\r\n        End If\r\n\r\n        Dts.TaskResult = ScriptResults.Success\r\n        Dts.TaskResult = ScriptResults.Success\r\n    End Sub\r\n\r\n#Region &quot;ScriptResults declaration&quot;\r\n    Enum ScriptResults\r\n        Success = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Success\r\n        Failure = Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure\r\n    End Enum\r\n#End Region\r\nEnd Class\r\n<\/pre>\n<p style=\"text-align: justify;\">This code also populates File_Exists variable which is being used in the Precedence Constraints joining the subsequent transformations. It contains the conditional expression which when evaluated, returns a Boolean value altering the package execution flow i.e. pointing it in either of the 2 directions \u2013 Execute SQL Task 1 or ForEach Loop Container 2. Below is the Precedence Constraint editor view for executing ForEach Loop Container 2 section.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_precedence_constraint_formula.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2202\" alt=\"Tablediff_SSIS_precedence_constraint_formula\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_precedence_constraint_formula.png\" width=\"580\" height=\"380\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_precedence_constraint_formula.png 630w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_precedence_constraint_formula-300x196.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">In the last section, ForEach Loop Container 2 iterates through SQL files created using the following enumerator configuration and variable mapping.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_ForEach_Loop2_Var_Mapping.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2208\" alt=\"Tablediff_ForEach_Loop2_Var_Mapping\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_ForEach_Loop2_Var_Mapping.png\" width=\"580\" height=\"119\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_ForEach_Loop2_Var_Mapping.png 580w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_ForEach_Loop2_Var_Mapping-300x61.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">Inside the ForEach Loop Container 2, Execute SQL Task 3 transformation runs the SQL statements saved in the files, with SQL Source Type property configured as a File Connection and Temp_FileName connection selected as a value for File Connection property. File System Task simply archives the processed files into the archive sub-directory as the last step of this package\u2019s execution.<\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_ForEach_Loop2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2210\" alt=\"Tablediff_SSIS_ForEach_Loop2\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_ForEach_Loop2.png\" width=\"580\" height=\"335\" \/><\/a><\/p>\n<p style=\"text-align: center;\"><a href=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_file_sys_task1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter  wp-image-2206\" alt=\"Tablediff_SSIS_file_sys_task1\" src=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/\/2014\/02\/Tablediff_SSIS_file_sys_task1.png\" width=\"580\" height=\"324\" srcset=\"http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_file_sys_task1.png 580w, http:\/\/bicortex.com\/bicortex\/wp-content\/post_content\/2014\/02\/Tablediff_SSIS_file_sys_task1-300x167.png 300w\" sizes=\"auto, (max-width: 580px) 100vw, 580px\" \/><\/a><\/p>\n<p style=\"text-align: justify;\">The complete package can be downloaded from my SkyDrive folder <a href=\"https:\/\/skydrive.live.com\/redir?resid=715AEF07A82832E1!57856&amp;authkey=!ABfhXRxFGwnYZgY&amp;ithint=folder%2c.bat\" target=\"_blank\"><b>HERE<\/b><\/a> so you can use it as a template &#8211; just make sure you adjust all necessary parameters e.g. database connection details etc. to correspond to your environment. I have also attached a short video footage depicting the package execution and the outcome on the tables\u2019 data synchronization and SQL files management.<\/p>\n<p><iframe loading=\"lazy\" src=\"http:\/\/www.youtube.com\/embed\/DRw2muCPe2c\" height=\"330\" width=\"580\" frameborder=\"0\"><\/iframe><\/p>\n<p style=\"text-align: justify;\">So there you go, a fairly simple and easy to manage data synchronization solution using tablediff utility and Integration Services tool. If you take away the VB.NET code snippet, the whole solution can be build using the default tablediff functionality, pure SSIS and one very simple SELECT SQL statement so if your project can live with the tablediff functionality constraints and you don\u2019t require a great deal of performance, this tool can become a simple and straightforward option for your data synchronization project.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the FIRST post this short series I briefly outlined tablediff utility and set the stage (databases, objects, directories and batch file) for the SSIS package responsible for data synchronization workflow. In this post I will continue with the solution development and show you how to build and configure the package to take advantage of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,50],"tags":[49,13],"class_list":["post-2182","post","type-post","status-publish","format-standard","hentry","category-sql","category-ssis","tag-sql","tag-ssis"],"aioseo_notices":[],"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/posts\/2182","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/comments?post=2182"}],"version-history":[{"count":21,"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/posts\/2182\/revisions"}],"predecessor-version":[{"id":2224,"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/posts\/2182\/revisions\/2224"}],"wp:attachment":[{"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/media?parent=2182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/categories?post=2182"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/bicortex.com\/bicortex\/wp-json\/wp\/v2\/tags?post=2182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}