Efficiently Compare Two SQL Server Tables Using Mostly VBScript
Recently, a friend of mine asked to write a script to compare two SQL Server tables using mostly VBScript. The very thought made me shudder; I wanted desperately to compare the tables in SQL Server but ultimately, the company's requirements prevented us from doing so. Here were the stipulations:
- First, the script should be as reusable as possible. Many tables will be compared.
- The column names are unknown -- only the database name and table were consistent.
- The SQL Servers were 2005 and both located on the same domain.
- Windows Authentication must be used.
- SSIS/DTS cannot be used.
- Files can be written to the hard drive, but only as a last resort.
- OPENROWSET/OPENDATASOURCE/Linked Servers cannot be used.
- The script's output must be either TRUE or FALSE. TRUE if the tables matched, FALSE if they didn't.
- IDENTITY columns must be ignored.
I told him I'd be back in 20 minutes as my brain figured it out. This is what it came up with:
- ADO's recordset getstring() will be used for direct comparisons. No variables will need to be assigned, no data will need to be written.
- The INFORMATION_SCHEMA will be queried to discover column names. Column names will be reused by both SELECT and ORDER BY.
- ORDER BY will be used to ensure the data is returned in the same order on both tables.
- COLUMNPROPERTY will be used to check if the column is an identity (I know excluding the ID means that the table may not be exactly a match, but it's what was requested, so I obliged.)
1strServer1 = "server1"
2strServer2 = "server2"
3strDatabaseName = "mydatabase"
4strTableName = "mytable"
5
6Call CompareTables(strServer1, strServer2, strDatabaseName, strTableName)
7
8Sub CompareTables(server1, server2, databaseName, tableName)
9
10 ' This is a SQL Server 2005 Connection String with Windows Authentication. Change as necessary.
11 connString1 = "Provider=SQLNCLI;Server=" & server1 & ";Database=" & databaseName & ";Integrated Security=SSPI;"
12 connString2 = "Provider=SQLNCLI;Server=" & server2 & ";Database=" & databaseName & ";Integrated Security=SSPI;"
13
14 ' Since this is a template script, we don't know what the columns are so we'll use the INFORMATION_SCHEMA to figure it out.
15 ' Not only will this be useful in the SELECT statement (SELECT col1, col2, col3) but also is necessary for the ORDER BY.
16 ' Because we'll be using a text comparison, columns and order by must be in the same exact order on both server1 and server2
17 strSQLColumns = "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" & tableName & "' " & _
18 "AND (COLUMNPROPERTY(OBJECT_ID('" & tableName & "'), column_name, 'IsIdentity')) != 1 " & _
19 "ORDER BY ORDINAL_POSITION ASC"
20
21 Set rsColumns = CreateObject("adodb.recordset")
22 rsColumns.Open strSQLColumns, connString1, 1, 1
23
24 If rsColumns.EOF And rsColumns.BOF Then
25 MsgBox "The table has no columns or does not exist."
26 rsColumns.Close
27 Set rsColumns = Nothing
28 WScript.Quit
29 Else
30 Do Until rsColumns.EOF
31 strColumns = strColumns & rsColumns("COLUMN_NAME") & ","
32 rsColumns.MoveNext
33 Loop
34 ' Take off last comma
35 strColumns = Left(strColumns, Len(strColumns) - 1)
36 rsColumns.Close
37 Set rsColumns = Nothing
38 End If
39
40 ' Ninja
41 strSQL = "SELECT " & strColumns & " FROM " & tableName & " ORDER BY " & strColumns & " ASC"
42
43 Set rsServer1 = CreateObject("adodb.recordset")
44 rsServer1.Open strSQL, connString1, 1, 1
45 If rsServer1.EOF And rsServer1.BOF Then
46 MsgBox "No Rows to Compare in Table 1"
47 rsServer1.Close
48 Set rsServer1 = Nothing
49 WScript.Quit
50 End If
51
52 Set rsServer2 = CreateObject("adodb.recordset")
53 rsServer2.Open strSQL, connString2, 1, 1
54 If rsServer2.EOF And rsServer2.BOF Then
55 MsgBox "No Rows to Compare in Table 2"
56 rsServer1.Close
57 Set rsServer1 = Nothing
58 rsServer2.Close
59 Set rsServer2 = Nothing
60 WScript.Quit
61 End If
62
63 If rsServer1.GetString() = rsServer2.GetString() Then
64 Result = True
65 Else
66 Result = False
67 End If
68
69 rsServer1.Close
70 Set rsServer1 = Nothing
71 rsServer2.Close
72 Set rsServer2 = Nothing
73
74 MsgBox Result
75
76End Sub
Although VBScript is a favorite of mine, I'm a bit surprised that it's still a requirement on a new project. Anyway, thanks for the distraction, friend. It was nice to get away from VM troubleshooting for a bit.