{"id":1732,"date":"2013-12-02T00:00:00","date_gmt":"2013-12-02T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/sql-server-tablediff-utility\/"},"modified":"2021-05-11T15:57:22","modified_gmt":"2021-05-11T15:57:22","slug":"sql-server-tablediff-utility","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/databases\/sql-server\/tools-sql-server\/sql-server-tablediff-utility\/","title":{"rendered":"SQL Server tablediff utility"},"content":{"rendered":"<div id=\"pretty\">\n<p class=\"start\">Among the many command-line utilities provided with  SQL Server, one of particular note is tablediff, a handy tool that lets you compare the data in two tables in order to  identify any discrepancies. Though originally intended primarily as a utility for troubleshooting non-convergence in a  replication topology, tablediff can actually be used to perform a row-by-row comparison of any two tables that share a  similar schema. Although it is not fast in doing so, it can &#160;be used for running automated unit tests for database routines. In addition, you can, with limitations, use the tool to  generate the T-SQL script necessary to update the data in the second table to conform to the first table, if  discrepancies are found.<\/p>\n<h1>Getting Started with the tablediff Utility<\/h1>\n<p>The best way to learn how to use the tablediff  utility is to see it in action. This article includes a number of examples that demonstrate how to compare tables that  contain both matching and non-matching data. The tables in our examples reside in databases on different SQL Server  instances, one SQL Server 2012, the other SQL Server 2008 R2, both installed on the same local system. However, you can  compare any two tables-within the same database or within different databases on the same or different servers-so if you  want to try out these examples on your system, modify the T-SQL code and example tablediff commands as necessary to  accommodate your setup.<\/p>\n<p>Now let&#8217;s get started. First we&#8217;ll compare identical  tables on the two SQL Server instances. To prepare the environment, I ran the following code on each instance to create  the <code>TableDiffDB<\/code>  database and the <code>DiffTest1<\/code>  table within the database:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">USE master;\nGO\n\nIF DB_ID('TableDiffDB') IS NOT NULL\nDROP DATABASE TableDiffDB;\nGO\n\nCREATE DATABASE TableDiffDB;\nGO\n\nUSE TableDiffDB;\nGO\n\nIF OBJECT_ID('DiffTest1', 'U') IS NOT NULL\nDROP TABLE DiffTest1;\nGO\n\nCREATE TABLE DiffTest1\n(\n&#160; DiffID INT IDENTITY(101, 1) PRIMARY KEY,\n&#160; DiffName VARCHAR(25) NOT NULL\n);\nGO\n\nINSERT INTO DiffTest1 (DiffName)\nVALUES ('test tablediff utility');\nGO 10\n\n<\/pre>\n<p>Notice that the  <code>DiffTest1<\/code>  table contains the <code>DiffID<\/code>  and <code>DiffName<\/code>  columns. I populated each row in the tables with the same <code>DiffName<\/code> value, but let the  <code>IDENTITY<\/code>  property populate the <code>DiffID<\/code> values, starting with <code>101<\/code>.<\/p>\n<p>That&#8217;s all you need to test the tablediff utility;  however, before you do, you might want to first prepare your Windows environment. Although tablediff is installed by  default, you cannot reference the utility without using the full path name or switching to the folder where the  executable file is stored. However, you can modify your operating system&#8217;s  <code>Path<\/code>  environmental variable to include the full path to that folder. Once you add the path, you can run the tool at a command  prompt without having to navigate to the utility&#8217;s folder. <\/p>\n<p>The process you use to modify the  <code>Path<\/code>  system variable varies from one Windows operating system to the next. In Windows 7, for example, one way to access the <code>Path<\/code>  variable is to open Control Panel, click <code>System<\/code>  <code>and<\/code> <code>Security<\/code>,  and then click <code>System<\/code>.  In the left pane, select <code>Advanced<\/code> <code>system<\/code> settings, which launches the  <code>System<\/code>  <code>Properties<\/code>  dialog box. On the <code>Advanced<\/code>  tab, click the <code>Environment<\/code> <code>Variables<\/code>  button. When the <code>Environmental<\/code> <code>Variables<\/code> dialog box appears, select the <code>Path<\/code>  variable in the <code>System<\/code>  variables list, and then click <code>Edit<\/code>. This launches the  <code>Edit<\/code> <code>System<\/code> <code>Variable<\/code>  dialog box. In the <code>Variable<\/code> <code>value<\/code>  text box, append the current value by adding a semi-colon and the path to the tablediff directory, as in  <code>;C:\\Program Files\\Microsoft SQL Server\\110\\com<\/code>.<\/p>\n<p>Once you&#8217;ve modified the  <code>Path<\/code>  variable, you&#8217;re ready to go. Open a command prompt window and enter the following command:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourcetable difftest1 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationtable DiffTest1<\/pre>\n<p class=\"Code\">Before we go into the command&#8217;s details, first note  that a tablediff command is a single-line operation. It wraps across multiple lines here because of margin limitations;  however, you should not press <b> Enter<\/b> until you&#8217;ve typed in the entire command.  <\/p>\n<p>Now let&#8217;s look at the command itself. After  specifying the <b> tablediff<\/b> command name, you must include the six options  contained in the example:<\/p>\n<ul>\n<li><b> -sourceserver:<\/b> The SQL Server instance that contains the table  used as the basis for the comparison. If it&#8217;s the default instance, specify only the server name.<\/li>\n<li><b>  -sourcedatabase:<\/b> The database on the source SQL Server instance  that contains the table used as the basis for the comparison.<\/li>\n<li><b>  -sourcetable:<\/b> The table in the source database that serves as  the basis for the comparison.<\/li>\n<li><b>  -destinationserver:<\/b> The SQL Server instance that contains the  table to be compared to the source table. If it&#8217;s the default instance, specify only the server name.<\/li>\n<li><b>  -destinationdatabase:<\/b> The database on the destination SQL Server  instance that contains the table to be compared to the source table.<\/li>\n<li><b>-destinationtable<\/b><b>:<\/b> The table in the destination database that  will be compared to the source table.<\/li>\n<\/ul>\n<p>The tablediff utility compares the data in the source  table to the table in the destination table. In the example above (as well as those to follow), the  <b> localhost\\sqlsrv2012<\/b> instance serves as  the source and the <b> localhost\\sqlsrv2008R2<\/b> instance serves as the destination. Be  aware, however, that when using the tablediff utility to compare two tables, the source table must be configured with a  primary key or an <b> IDENTITY<\/b>  or <b> ROWGUID<\/b>  column.<\/p>\n<div class=\"note\">\n<p class=\"note\">NOTE: The tablediff utility uses Windows authentication to connect to SQL  Server. However, you can also specify a username and password when connecting to the source instance, the destination  instance, or both. For information about the login-related options (as well as details about other tablediff options),  see the Books Online topic &#8220;<a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/ms162843.aspx\">tablediff  Utility<\/a>.&#8221;<\/p>\n<\/div>\n<p>As you saw in the example, when specifying an option  in the tablediff command, you include the option name, preceded by a hyphen and followed by the option value, if one is  required. In this case, the option values are the source and destination SQL Server instances, the  <code>TableDiffDB<\/code>  databases, and the <code>DiffTest1<\/code> tables. When we run the command, it returns the information shown in Figure 1.<\/p>\n<p class=\"illustration\"> \t<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1907-clip_image001-630x202.jpg\" height=\"202\" width=\"630\" alt=\"1907-clip_image001-630x202.jpg\" \/><\/p>\n<p class=\"caption\"><b>Figure 1: Comparing tables in two different databases<\/b><\/p>\n<p>Notice that the results indicate that the tables are  identical. In other words, they share a similar schema and contain the same data. In this case, the example compares  tables defined in the default schema, <b> dbo<\/b>, but you might need to compare tables within other schemas.  To demonstrate how this work, we need to first add a schema to each of our databases and then create a table within that  schema, as shown in the following T-SQL script:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF SCHEMA_ID('diff') IS NULL\nEXECUTE('CREATE SCHEMA diff');\nGO\n\nIF OBJECT_ID('diff.DiffTest2', 'U') IS NOT NULL\nDROP TABLE diff.DiffTest2;\nGO\n\nCREATE TABLE diff.DiffTest2\n(\n&#160; DiffID INT IDENTITY(101, 1) PRIMARY KEY,\n&#160; DiffName VARCHAR(25) NOT NULL\n);\nGO\n\nINSERT INTO diff.DiffTest2 (DiffName)\nVALUES ('test tablediff utility');\nGO 10\n<\/pre>\n<p>The script creates a schema named  <b> diff<\/b>  and a table named <b> DiffTest2<\/b>  within that schema. Once again, we have two identical tables that we can compare. However, our tablediff command must  now include the <b> -sourceschema<\/b> and  <b>  -destinationschema<\/b> options:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest2 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest2<\/pre>\n<p class=\"Code\">As you can see, the command now points to the  <b> DiffTest2<\/b>  table and includes the schema-related options. Otherwise, the command is the same as the preceding example. In addition,  the results of this command, like the results of the preceding one, indicate that the table data is identical.<\/p>\n<p>Of course, the data won&#8217;t always be the same between  the two tables. For example, suppose we add the following five rows to the  <b> DiffTest2<\/b>  destination table: <\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">INSERT INTO diff.DiffTest2 (DiffName)\nVALUES ('another tablediff test');\nGO 5\n<\/pre>\n<p>If we now rerun the last tablediff command, our  results will be quite different, as shown in Figure 2.<\/p>\n<p class=\"illustration\"> \t<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1907-clip_image003-630x276.jpg\" height=\"276\" width=\"630\" alt=\"1907-clip_image003-630x276.jpg\" \/><\/p>\n<p class=\"caption\"><b>Figure 2: Using the tablediff utility to view the  differences between table data<\/b><\/p>\n<p>This time around, the results show that there are  five differences between the two tables. The results also list the primary key values for each row in the destination  table that does not exist in the source. <\/p>\n<p>Now let&#8217;s look at an example in which the data  differences between the compared tables are a bit more complex. But first, we need to create those tables. The following  T-SQL script adds the <b>  diff.DiffTest3<\/b> table to the source SQL Server instance:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('diff.DiffTest3', 'U') IS NOT NULL\nDROP TABLE diff.DiffTest3;\nGO\n\nCREATE TABLE diff.DiffTest3\n(\n&#160; DiffID INT IDENTITY(101, 1) PRIMARY KEY,\n&#160; DiffName VARCHAR(25) NOT NULL,\n&#160; DiffGuid UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID()\n);\nGO\n\nINSERT INTO diff.DiffTest3 (DiffName)\nVALUES ('test tablediff utility');\nGO 10\n<\/pre>\n<p>Notice that we&#8217;ve added the  <b> DiffGuid<\/b>  column, using the <b> NEWID<\/b>  function to assign a <b> GUID<\/b>  to each new row. We then add 10 rows to the table. Next, we add the same table to the destination instance, only we  change the configuration of the <b> IDENTITY<\/b>  property:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('diff.DiffTest3', 'U') IS NOT NULL\nDROP TABLE diff.DiffTest3;\nGO\n\nCREATE TABLE diff.DiffTest3\n(\n&#160; DiffID INT IDENTITY(101, 2) PRIMARY KEY,\n&#160; DiffName VARCHAR(25) NOT NULL,\n&#160; DiffGuid UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID()\n);\nGO\n\nINSERT INTO diff.DiffTest3 (DiffName)\nVALUES ('test tablediff utility');\nGO 10\n<\/pre>\n<p>By modifying the  <b> IDENTITY<\/b>  property to increment values by two, rather than one, we offset the primary key values between the tables in order to  complicate the data differences. We can then update our tablediff command to reference the two new tables:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest3 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest3<\/pre>\n<p class=\"Code\">When we run the command, the results will now show  when a row exists only in the source table, only in the destination, or in both, but with values that don&#8217;t match, as  shown in Figure 3.<\/p>\n<p class=\"illustration\"> \t<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1907-clip_image005-630x351.jpg\" height=\"351\" width=\"630\" alt=\"1907-clip_image005-630x351.jpg\" \/><\/p>\n<p class=\"Caption\"><b>Figure3: Comparing tables with multiple types of  mismatches<\/b><\/p>\n<p>As you can see, there are 15 differences between the  two tables, five of which are mismatches. Because the comparison between the two tables is based on the primary key, the  mismatched rows are those with the same primary key, but different <b> DiffGuid<\/b> values. The other differences  are rows with a primary key value in the source table or destination table, but not both.<\/p>\n<h1>Failed comparisons<\/h1>\n<p>To be able to use the tablediff utility to compare  tables, the tables must share a similar schema. As a result, the tables must have the same number of columns and the  compared columns must be defined with the same name and compatible data types. You can, for example, compare a  <b> smallint<\/b>  column in the source table with an <b> int<\/b> column in the destination table, but you cannot compare a <b> smallint<\/b>  column with an <b> nvarchar<\/b>  column.<\/p>\n<div class=\"note\">\n<p class=\"note\">NOTE: The tablediff utility also supports the  <b> -strict<\/b>  option. When used, the data types must match exactly between the two tables in order to perform the comparison.<\/p>\n<\/div>\n<p>If you try to compare two tables that don&#8217;t share a  similar schema, the tablediff utility returns a message saying that the tables cannot be compared. For example, suppose  we compare the <b> DiffTest2<\/b>  table on the source instance with the <b> DiffTest3<\/b> table on the destination instance, as shown in the  following command:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest2 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest3<\/pre>\n<p class=\"Code\">When we run the command, we receive the results shown  in Figure 4. Notice they include a message indicating that tables with different schemas cannot be compared.<\/p>\n<p class=\"illustration\"> \t<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1907-clip_image007-630x219.jpg\" height=\"219\" width=\"630\" alt=\"1907-clip_image007-630x219.jpg\" \/><\/p>\n<p class=\"caption\"><b>Figure 4: Trying to compare tables with different schemas<\/b><\/p>\n<p>You&#8217;ll also run into a similar issue if you try to  compare tables in which one doesn&#8217;t exist. For example, suppose we add the following table to our source instance:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">IF OBJECT_ID('diff.DiffTest4', 'U') IS NOT NULL\nDROP TABLE diff.DiffTest4;\nGO\n\nCREATE TABLE diff.DiffTest4\n(\n&#160; DiffID INT IDENTITY(101, 1) PRIMARY KEY,\n&#160; DiffName VARCHAR(25) NOT NULL,\n&#160; DiffGuid UNIQUEIDENTIFIER NOT NULL DEFAULT NEWID()\n);\nGO\n\nINSERT INTO diff.DiffTest4 (DiffName)\nVALUES ('test tablediff utility');\nGO 10\n<\/pre>\n<p>Now suppose that, after we create and populate the <b> DiffTest4<\/b> table on our source, we assume that it&#8217;s been  replicated to the destination server and we run the following command:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest4 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest4<\/pre>\n<p class=\"Code\">This time around, the tablediff command returns a  slightly different message, but the sentiment is the same, as shown in Figure 5.<\/p>\n<p class=\"illustration\"> \t<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1907-clip_image009-630x234.jpg\" height=\"234\" width=\"630\" alt=\"1907-clip_image009-630x234.jpg\" \/><\/p>\n<p class=\"caption\"><b>Figure 5: Message returned by the tablediff utility when  the destination table doesn&#8217;t exist<\/b><\/p>\n<p>The message indicates that destination table doesn&#8217;t  exist or we don&#8217;t have permission to access the table. A second message says that different schemas can&#8217;t be compared.  Certainly, if one table exists and the other does not, we can comfortably assume the two tables don&#8217;t share the same  schema.<\/p>\n<h1>Outputting Comparison Results<\/h1>\n<p>Up to this point, the example commands we&#8217;ve looked  at displayed their results in the command shell window. However, we can instead send those results to a text file in  order to log the information. To do so, we add the <b> -o<\/b> option followed by the full path and  filename of the target text file, as shown in the following example:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest3 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest3 -o c:\\datafiles\\tablediff\\results.txt<\/pre>\n<p class=\"Code\">As you saw in an earlier example, we&#8217;re simply  comparing the <b> DiffTest3<\/b> table on each SQL Server instance. The only new element  in the command is the <b> -o<\/b> argument, which specifies that the  output be saved to the <b> results.txt<\/b> file. After we run the command, the output file will  contain the following results:<\/p>\n<pre>Table [tablediffdb].[diff].[difftest3] on localhost\\sqlsrv2012 and Table [tablediffdb].[diff].[DiffTest3] on localhost\\sqlsrv2008r2 have 15 differences.\nErr&#160;&#160; DiffID\nMismatch&#160;&#160;&#160; 101\nSrc. Only&#160;&#160; 102\nMismatch&#160;&#160;&#160; 103\nSrc. Only&#160;&#160; 104\nMismatch&#160;&#160;&#160; 105\nSrc. Only&#160;&#160; 106\nMismatch&#160;&#160;&#160; 107\nSrc. Only&#160;&#160; 108\nMismatch&#160;&#160;&#160; 109\nSrc. Only&#160;&#160; 110\nDest. Only&#160; 111\nDest. Only&#160; 113\nDest. Only&#160; 115\nDest. Only&#160; 117\nDest. Only&#160; 119\nThe requested operation took 0.09375 seconds.\n\t<\/pre>\n<p>The tablediff tool also offers a second option for  persisting the utility&#8217;s results. Instead of saving them to an output file, we save them to a table in the destination  database. The tablediff utility provides two arguments that support this functionality. The  <b> -et<\/b>  argument specifies the name of the table, and the <b> -dt<\/b> argument indicates that the table  identified in the <b> -et<\/b> argument should be dropped if it already exists. The  following example shows how to use these two arguments to save the results to a table named  <b>  DiffResults<\/b>:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest3 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest3 -dt -et DiffResults<\/pre>\n<p class=\"Code\">Notice that I&#8217;ve replaced the  <b> -o<\/b>  argument with the <b> -dt<\/b>  argument and the <b> -et<\/b>  argument and table name. After we run the command, we can retrieve the results by running a query similar to the  following in our destination database:<\/p>\n<pre class=\"theme:ssms2012 lang:tsql\">SELECT* FROM DiffResults;<\/pre>\n<p>The <b> SELECT<\/b> statement returns the results  shown in the following table. This is the data outputted by the tablediff command and saved to that table.<\/p>\n<table class=\"MsoTableGrid\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"><b> \t\tDiffID<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"><b> \t\t \t\tMSdifftool_ErrorCode<\/b><\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"><b> \t\t \t\tMSdifftool_ErrorDescription<\/b><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t101<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t0<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tMismatch<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t102<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tSrc. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t103<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t0<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tMismatch<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t104<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tSrc. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t105<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t0<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tMismatch<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t106<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tSrc. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t107<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t0<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tMismatch<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t108<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tSrc. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t109<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t0<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tMismatch<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t110<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t2<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tSrc. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t111<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tDest. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t113<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tDest. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t115<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tDest. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t117<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tDest. Only<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t119<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\t1<\/p>\n<\/td>\n<td valign=\"top\">\n<p class=\"Code\"> \t\tDest. Only<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>You might have noticed that the table contains  information we haven&#8217;t seen before-the error codes. These are fairly straightforward and correlate directly to the error  messages. The <b> 0<\/b>  indicates a mismatch, the <b> 1<\/b> indicates that the destination contains a row not contained in  the source, and the <b> 2<\/b> indicates that the source contains a row not in the  destination. Again, these error codes (and their related descriptions) are tied to the primary key values.<\/p>\n<h1>Generating T-SQL Scripts<\/h1>\n<p>One of the handiest features of the tablediff utility  is the ability to generate a T-SQL script that includes the data manipulation language (DML) statements necessary to  update the destination table in order to bring it inline with the source table. To generate the script, we need only add  the <b> -f<\/b> option, followed by the full path and filename of the script  file. For example, the following command again compares the <b> DiffTest3<\/b>  tables in each SQL Server instance, only this time also generates the DML script file:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest3 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest3 -o c:\\datafiles\\tablediff\\results.txt -f c:\\datafiles\\tablediff\\script.sql<\/pre>\n<p class=\"Code\">As we did in an earlier example, we&#8217;re saving our  output to the <b> results.txt<\/b> file (rather than a SQL Server table). We&#8217;re also  using the <b> -f<\/b>  option to generate the T-SQL script and save it to the <b> script.sql<\/b> file. If we were to view the  script file after running the command, we would find the following contents:<\/p>\n<pre>-- Host: localhost\\sqlsrv2008r2\n-- Database: [tablediffdb]\n-- Table: [diff].[DiffTest3]\nSET IDENTITY_INSERT [diff].[DiffTest3] ON\nUPDATE [diff].[DiffTest3] SET [DiffGuid]='c659a110-6780-44ab-bd4f-624136035630' WHERE [DiffID] = 101\nINSERT INTO [diff].[DiffTest3] ([DiffGuid],[DiffID],[DiffName]) VALUES ('dae4b8f7-10b6-4e4e-bf69-242cb77eeb63',102,N'test tablediff utility')\nUPDATE [diff].[DiffTest3] SET [DiffGuid]='0af314a1-5753-4e5f-83d8-f99d28750110' WHERE [DiffID] = 103\nINSERT INTO [diff].[DiffTest3] ([DiffGuid],[DiffID],[DiffName]) VALUES ('7a54ad98-8659-40ab-8519-4dfd6cbc9492',104,N'test tablediff utility')\nUPDATE [diff].[DiffTest3] SET [DiffGuid]='a404dc92-5253-4962-8a6c-5fa1cbf6bc53' WHERE [DiffID] = 105\nINSERT INTO [diff].[DiffTest3] ([DiffGuid],[DiffID],[DiffName]) VALUES ('2e6f4a64-851a-419b-bc92-b565e52dbcd4',106,N'test tablediff utility')\nUPDATE [diff].[DiffTest3] SET [DiffGuid]='6078117d-9622-4c35-8e04-6d88665a5698' WHERE [DiffID] = 107\nINSERT INTO [diff].[DiffTest3] ([DiffGuid],[DiffID],[DiffName]) VALUES ('c1991f55-f1df-4e7f-bc24-e6061a14eba4',108,N'test tablediff utility')\nUPDATE [diff].[DiffTest3] SET [DiffGuid]='fdb1cc7f-c6e4-47b2-a623-9ccaa5d20b59' WHERE [DiffID] = 109\nINSERT INTO [diff].[DiffTest3] ([DiffGuid],[DiffID],[DiffName]) VALUES ('e67badcb-ab16-403a-97a8-5a84f678454a',110,N'test tablediff utility')\nDELETE FROM [diff].[DiffTest3] WHERE [DiffID] = 111\nDELETE FROM [diff].[DiffTest3] WHERE [DiffID] = 113\nDELETE FROM [diff].[DiffTest3] WHERE [DiffID] = 115\nDELETE FROM [diff].[DiffTest3] WHERE [DiffID] = 117\nDELETE FROM [diff].[DiffTest3] WHERE [DiffID] = 119\nSET IDENTITY_INSERT [diff].[DiffTest3] OFF\n\n<\/pre>\n<p>As expected, our script file contains all the  <b> INSERT<\/b>, <b> UPDATE<\/b>,  and <b> DELETE<\/b>  statements necessary to modify the data in the <b> DiffTest3<\/b> table in the destination  database so the data can be brought into sync with the source table. Beware, though, that the synchronization feature doesn&#8217;t work with&#160;varchar(max) nvarchar(max), varbinary(max), timestamp, xml, text, ntext or image datatypes so is of limited usefulness.<\/p>\n<p>Also worth noting is the contents of the  <b>  results.txt<\/b> file. When we generate a T-SQL script, the command&#8217;s output also includes the  name of the column where a mismatch exists, as the following file contents show:<\/p>\n<pre>Table [tablediffdb].[diff].[difftest3] on localhost\\sqlsrv2012 and Table [tablediffdb].[diff].[DiffTest3] on localhost\\sqlsrv2008r2 have 15 differences.\nFix SQL written to c:\\datafiles\\tablediff\\script.sql.\nErr&#160;&#160; DiffID&#160;&#160;&#160;&#160;&#160; Col\nMismatch&#160;&#160;&#160; 101&#160;&#160; DiffGuid \nSrc. Only&#160;&#160; 102&#160;&#160; \nMismatch&#160;&#160;&#160; 103&#160;&#160; DiffGuid \nSrc. Only&#160;&#160; 104&#160;&#160; \nMismatch&#160;&#160;&#160; 105&#160;&#160; DiffGuid \nSrc. Only&#160;&#160; 106&#160;&#160; \nMismatch&#160;&#160;&#160; 107&#160;&#160; DiffGuid \nSrc. Only&#160;&#160; 108&#160;&#160; \nMismatch&#160;&#160;&#160; 109&#160;&#160; DiffGuid \nSrc. Only&#160;&#160; 110&#160;&#160; \nDest. Only&#160; 111&#160;&#160; \nDest. Only&#160; 113&#160;&#160; \nDest. Only&#160; 115&#160;&#160; \nDest. Only&#160; 117&#160;&#160; \nDest. Only&#160; 119&#160;&#160; \nThe requested operation took 0.078125 seconds.\n<\/pre>\n<p class=\"Code\">In this case, our mismatches occur in the  <b> DiffGuid<\/b>  column. If we had not generated the T-SQL script, this information would not have been included in the results, unless  we had added another option to our command, as you&#8217;ll see in the next section.<\/p>\n<h1>Modifying the Command Output<\/h1>\n<p>In the last example, you saw how the output file  contains the names of the mismatched column. However, if you do not create a script file when returning the results, the  output will not contain the column information unless you add the <b> -c<\/b> option to your command, as shown in  the following example: <\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest3 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest3 -c<\/pre>\n<p class=\"Code\">In this case, we&#8217;ve taken a basic command and simply  added the <b> -c<\/b> option. The results will now include the column information,  as shown in Figure 6.<\/p>\n<p class=\"illustration\"> <img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1907-clip_image011-630x358.jpg\" height=\"358\" width=\"630\" alt=\"1907-clip_image011-630x358.jpg\" \/><\/p>\n<p class=\"caption\"><b>Figure 6: Viewing the columns in which data is mismatched<\/b><\/p>\n<p>Another tablediff option to be aware of is the  <b> -q<\/b> option, which specifies that only a fast comparison be  performed. When you include this option, the utility compares only the schema and row counts. For example, the  following command again compares the <b> DiffTest3<\/b>  tables, but now includes the <b> -q<\/b> option:<\/p>\n<pre>tablediff -sourceserver localhost\\sqlsrv2012 -sourcedatabase tablediffdb -sourceschema diff -sourcetable difftest3 -destinationserver localhost\\sqlsrv2008r2 -destinationdatabase tablediffdb -destinationschema diff -destinationtable DiffTest3 -q<\/pre>\n<p class=\"Code\">As you can see in Figure 7, the results show that the  tables are identical, each table sharing the same schema and number of rows.<\/p>\n<p class=\"illustration\"> \t<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1907-clip_image013-630x243.jpg\" height=\"243\" width=\"630\" alt=\"1907-clip_image013-630x243.jpg\" \/><\/p>\n<p class=\"caption\"><b>Figure 7: Using the tablediff utility to compare row counts  and schema differences<\/b><\/p>\n<p>The problem with the  <b> -q<\/b>  option, as you probably noticed, is that it fails to take into account actual differences in the data. As you&#8217;ll recall  from when we created and populated these tables, there are a number of issues. Although the schema is similar, as  are the number of rows, the data in those rows is different. So the <b> -q<\/b>  option might be useful for a quick comparison, but don&#8217;t assume the data is the same because the results show identical  tables.<\/p>\n<h1>Using PowerShell to Compare Databases<\/h1>\n<p>At times, you might want to use the tablediff utility  to compare multiple tables in a database without having to manually enter the command for each comparison. That&#8217;s where  PowerShell comes in. You can create a PowerShell script that uses the tablediff utility to compare each matching table  in two databases.<\/p>\n<p>To run such a script, the SQL Server PowerShell  provider must be installed in order to navigate the SQL Server objects. The provider is installed by default when you  run PowerShell from SQL Server Management Studio (SSMS). However, if you want to access SQL Server from a regular  PowerShell command prompt, you must import the <b> sqlps<\/b>  module into PowerShell by running the following command:<\/p>\n<pre>Import-Module \"sqlps\" -DisableNameChecking<\/pre>\n<p class=\"Code\">The command uses the  <b>  Import-Module<\/b> cmdlet to import the <b> sqlps<\/b>  module. By default, when you import the module, it changes the provider to  <b> SQLSERVER<\/b>.  But you can change it back to your current directory by entering a command similar to the following:<\/p>\n<pre>cd c:<\/pre>\n<p class=\"Code\">The approach you take to scripting your tablediff  operations depends on whether multiple schemas are involved. For example, suppose we want to compare tables in the <b> AdventureWorks2012<\/b> and  <b>  AdventureWorks2008R2<\/b> databases. We can use a couple  <b> foreach<\/b> loops to retrieve the schema names and then retrieve the  table names in each schema, as shown in the following PowerShell script:<\/p>\n<pre>$OutFolder = \"C:\\DataFiles\\TableDiff\\\"\n$OutResults = $OutFolder + \"output.txt\"\n\n$SourceSrv = \"localhost\\SqlSrv2012\"\n$SourceDb = \"AdventureWorks2012\"\n$DestSrv = \"localhost\\SqlSrv2008R2\"\n$DestDb = \"AdventureWorks2008R2\"\n\n$schemas = Get-ChildItem SQLSERVER:\\SQL\\$SourceSrv\\Databases\\$SourceDb\\schemas\\ | select name\n\nforeach ($schema in $schemas)\n{\n\n&#160; $tables = Get-ChildItem SQLSERVER:\\SQL\\$SourceSrv\\Databases\\$SourceDb\\tables\\ | where {$_.schema -eq $schema.name} | select name\n\n&#160; foreach ($table in $tables)\n&#160; {\n\n&#160;&#160;&#160; $OutSql = $OutFolder + $schema.name + \".\" + $table.name + \".sql\"\n\n&#160;&#160;&#160; tablediff -sourceserver $SourceSrv -sourcedatabase $SourceDb -sourceschema $schema.name -sourcetable $table.name -destinationserver $DestSrv -destinationdatabase $DestDb -destinationschema $schema.name -destinationtable $table.name -f $OutSql -o $OutResults\n\n&#160; }\n\n}\n<\/pre>\n<p class=\"Code\">The first task is to declare variables that identify  the folder to use as the target folder (<b>C:\\DataFiles\\TableDiff\\<\/b>) and the file to  use for the output of each operation (<b>output.txt<\/b>).<\/p>\n<pre>$OutFolder = \"C:\\DataFiles\\TableDiff\\\"\n$OutResults = $OutFolder + \"output.txt\"\n\t<\/pre>\n<p>Next, we declare the variables necessary to identify  the source and destination SQL Server instances and databases:<\/p>\n<pre>$SourceSrv = \"localhost\\SqlSrv2012\"\n$SourceDb = \"AdventureWorks2012\"\n$DestSrv = \"localhost\\SqlSrv2008R2\"\n$DestDb = \"AdventureWorks2008R2\"\n\t<\/pre>\n<p>So far, all fairly clear-cut. The next step is only  slightly more complicated. We declare the <b> $schemas<\/b>  variable, which uses the <b> Get-ChildItem<\/b> cmdlet and  <b> SQLSERVER<\/b> provider to retrieve the name  of each schema in the source database:<\/p>\n<pre>$schemas = Get-ChildItem SQLSERVER:\\SQL\\$SourceSrv\\Databases\\$SourceDb\\schemas\\ | select name<\/pre>\n<p>Note that this approach retrieves all schemas but <b> dbo<\/b>,  which is what we want in this case, but if you want to include <b> dbo<\/b>, you would need to add the necessary  logic. We then pipe the results to the <b> Select-Object<\/b> cmdlet, which specifies  that we return only the <b> name<\/b> property. (In this case, we&#8217;re using  the <b> select<\/b> alias to reference the cmdlet.)<\/p>\n<p>The next step is to set up the first  <b> foreach<\/b>  loop to iterate through the list of schemas:<\/p>\n<pre>foreach ($schema in $schemas)<\/pre>\n<p class=\"Code\">The <b> $schema<\/b> variable will hold the name of  each schema in <b> $schemas<\/b> as we iterate through the list. From there, we can then  retrieve our tables for that schema and save it to the <b> $tables<\/b> variable:<\/p>\n<pre>$tables = Get-ChildItem SQLSERVER:\\SQL\\$SourceSrv\\Databases\\$SourceDb\\tables\\ | where {$_.schema -eq $schema.name} | select name<\/pre>\n<p class=\"Code\">We again use the  <b>  Get-ChildItem<\/b> cmdlet and <b> SQLSERVER<\/b>  provider, but this time to retrieve a list of tables in the specified schema. Next, we embed a second  <b> foreach<\/b> loop in the first  <b> foreach<\/b> loop in order to retrieve each  table from the set of tables:<\/p>\n<pre>foreach ($table in $tables)<\/pre>\n<p class=\"Code\">The <b> $table<\/b> variable stores the name of each  table as we loop through the list of tables. Within that loop, we also specify the name of the file to hold the T-SQL  script, saving this information to the <b> $OutSql<\/b>  variable:<\/p>\n<pre>$OutSql = $OutFolder + $schema.name + \".\" + $table.name + \".sql\"<\/pre>\n<p>The filename is based on a combination of the current  schema and table names. After we define the logic for our script file, we create our tablediff command, using the  different variables to provide our option values:<\/p>\n<pre>tablediff -sourceserver $SourceSrv -sourcedatabase $SourceDb -sourceschema $schema.name -sourcetable $table.name -destinationserver $DestSrv -destinationdatabase $DestDb -destinationschema $schema.name -destinationtable $table.name -f $OutSql -o $OutResults<\/pre>\n<p class=\"Code\">Each time PowerShell iterates through the embedded <b> foreach<\/b> loop, it will run a comparison of the table currently in  the <b> $table<\/b> variable. The results will then be added to the  <b>  output.txt<\/b> file, and the T-SQL script will be generated and saved to a file whose name is  based on the schema and table name.<\/p>\n<p>That&#8217;s all there is to creating a basic script to  compare tables and generate the necessary update scripts. You can, of course, parameterize the PowerShell script to make  it reusable. You can also include error handling and any other components to refine the script to meet your needs. But  the script shown here should give you the foundation you need to get started.<\/p>\n<h1>Making the Most of the tablediff Utility<\/h1>\n<p>If you haven&#8217;t already discovered the tablediff  utility, you&#8217;ll find it well worth your time to check it out. The tool is part of the SQL Server installation and is  relatively simple to use. Just open a command prompt window and start typing. Not only can you compare tables across SQL  Server instances, but you can also generate the T-SQL scripts necessary to update those tables just so long as they don&#8217;t contain LOB data such as Varchar(MAX). And you can run the  utility from within scripts created in command shells such as PowerShell, thus letting you automate operations and reuse  code. The tablediff utility might not meet all your needs when comparing tables, but in those cases where it does,  you&#8217;ll likely find tablediff to be a valuable addition to your arsenal of tools.<\/p>\n<\/p><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Rob Sheldon continues on his quest to explain all those command-line tools such as SQLCMD, Logparser, SQLIO and tablediff that are part of SQL Server. TableDiff can be used for comparing tables, as when you run automated tests that check a result against a table of expected values. The best way to learn TableDiff is to see it in action and Rob talks you through several examples.&hellip;<\/p>\n","protected":false},"author":221841,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143532],"tags":[4150,4151,4213],"coauthors":[],"class_list":["post-1732","post","type-post","status-publish","format-standard","hentry","category-tools-sql-server","tag-sql","tag-sql-server","tag-sql-tools"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1732","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/221841"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1732"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1732\/revisions"}],"predecessor-version":[{"id":90954,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1732\/revisions\/90954"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1732"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1732"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1732"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1732"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}