Working With Offline SQL Server Data in Excel
Working With Offline SQL Server Data in Excel
Brian A. Randell MCW Technologies, LLC Applies to: Microsoft Visual Studio Tools for the Microsoft Office System Summary: Excel makes it easy to work rectangular data such as data from an external database. In this walkthrough, youll load data from SQL Server into an ADO.NET Dataset. Youll then use Excels object model to support synchronizing changes made to the data in Excel with SQL Server. (11 printed pages)
Contents
Getting Started Hook Up the Event Handlers Add Code to Import Data Synchronize Changes with the Server Run Code Before Closing the Workbook
Introduction
Youll download data from the SQL Server Northwind sample database into a local DataSet object, releasing your connection to the server. Youll then load the data from the dataset into a sheet within an Excel workbook as shown in Figure 1. Once the data is loaded, youll make some changes and send the results back to SQL Server. Once youre done, the example will display a message box informing you of the number of records updated.
Prerequisites
To follow this walkthrough, the following software and components must be installed on the development computer: Microsoft Visual Studio .NET 2003 or Microsoft Visual Basic .NET Standard 2003 Microsoft Visual Studio Tools for the Microsoft Office System Microsoft Office Professional 2003 SQL Server or MSDE (7.0 or 2000), with the Northwind sample database installed. This demonstration assumes that youve set up SQL Server/MSDE allowing access using integrated security.
Although its not required, this demonstration assumes that youve set the Option Strict setting in your project to On (or have added the Option Strict statement to each module in your project.) Setting the Option Strict setting to On requires a bit more code, as youll see, but it also ensures that you dont perform any unsafe type conversions. You can get by without it, but in the long run, the discipline required by taking advantage of this option will far outweigh the difficulties it adds as you write code.
TIP:
Getting Started
In order to get started, youll need to begin by creating a new Visual Studio .NET project that works with Excel.
7. Repeat the process, putting the cursor in cell G2, and put Update Data in the Text to display field. 8. Select File, Save to save your changes. The workbook should look something like Figure 3.
1. From the Class Name dropdown list in the upper-left corner of the code editor window, select ThisWorkbook. 2. From the Method Name dropdown list in the upper-right corner of the code editor window, select SheetFollowHyperlink. Visual Studio .NET creates the event handler stub for you. 3. Add the following procedure stubs to the current class. Youll fill in the details later:
Private Sub LoadData() End Sub Private Sub UpdateData() End Sub
2. Add the following declarations, immediately beneath the existing declarations for the ThisApplication and ThisWorkbook variables:
Private DisableWorkSheetChanges As Boolean = False Private mda As SqlDataAdapter
Private mds As DataSet Private mdt As System.Data.DataTable Private xlSheet As Excel.Worksheet Private rngUC As Excel.Range Private rngData As Excel.Range
WARNING!
Excel provides a DataTable object, as does ADO.NET. Its important to distinguish between the two, and the code uses an explicit namespace reference to avoid the ambiguity.
3. Add the following procedure to the OfficeCodeBehind class. This procedure connects to SQL Server on the local computer, using integrated security, and fills a DataSet:
Private Sub GetDataSet() Dim cnn As SqlConnection Try If mds Is Nothing Then mds = New DataSet Else mds.Tables.Remove(mdt) End If cnn = New SqlConnection( _ "Server='.';" & _ "Database=Northwind;" & _ "Integrated Security=true") Dim strSQL As String = "SELECT " & _ "ProductId AS [Id], ProductName AS [Name], " & _ "UnitsInStock AS [On Hand], " & _ "UnitsOnOrder AS [On Order], " & _ "ReorderLevel AS [Reorder Level] " & _ "FROM Products WHERE Discontinued = 0 " & _ "ORDER BY UnitsInStock" Dim cmd As New SqlCommand(strSQL, cnn) mda = New SqlDataAdapter(cmd) mda.Fill(mds) mdt = mds.Tables(0)
Dim cb As New SqlCommandBuilder(mda) mda.UpdateCommand = cb.GetUpdateCommand() Catch ex As Exception MessageBox.Show(ex.Message, ex.Source, _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Sub
4. Add the following procedure to the class. This procedure creates the column headings in the worksheet using the field names from the Columns collection of the DataTable contained within the new DataSet, and provides basic formatting:
Private Sub SetupWorksheet() Try DisableWorkSheetChanges = True xlSheet = DirectCast( _ ThisWorkbook.Worksheets("Products"), Excel.Worksheet) rngUC = DirectCast(xlSheet.Cells(2, 1), Excel.Range) rngUC.CurrentRegion.Clear() Dim i As Integer = 0 Dim col As DataColumn Dim rng As Excel.Range For Each col In mdt.Columns I += 1 rng = DirectCast(xlSheet.Cells(1, i), Excel.Range) rng.Value = col.ColumnName rng.Font.Bold = True Next Finally DisableWorkSheetChanges = False End Try End Sub
5. Add the following procedure, which takes the data from the DataTable in the previously loaded DataSet and puts it into the Products worksheet:
Private Sub PutDataInXL() DisableWorkSheetChanges = True Dim i As Integer = 0 Dim j As Integer = 0 Dim dr As DataRow
Try ThisApplication.ScreenUpdating = False If Not mdt Is Nothing Then For i = 0 To mdt.Rows.Count - 1 dr = mdt.Rows(i) For j = 0 To mdt.Columns.Count - 1 rngUC.Offset(i, j).Value = dr(j).ToString() Next j Next rngData = rngUC.CurrentRegion End If Finally ThisApplication.ScreenUpdating = True DisableWorkSheetChanges = False End Try End Sub
6. Add the following procedure, which applies some formatting to the newly loaded data in Excel:
Private Sub FormatColumns() Try DisableWorkSheetChanges = True rngData.Columns.NumberFormat = "0" rngData.Columns.AutoFit() Finally DisableWorkSheetChanges = False End Try End Sub
8. Select File, Save All to save the entire solution. 9. Press F5 to run the project, loading Excel and your workbook. 10. Within Excel, click the Load Data link you added previously, and verify that your code has imported and formatted the data, as shown in Figure 1.
11. Close the Excel and the workbook, saving changes if you desire, and return to Visual Studio .NET.
4. Add the following code to the existing UpdateData procedure stub, sending the DataTables modified rows to SQL Server:
Try If mds.HasChanges Then Dim intRV As Integer = mda.Update(mdt) If intRV > 0 Then
MessageBox.Show(String.Format( _ "{0} records were updated successfully.", _ intRV.ToString()), _ "Success", MessageBoxButtons.OK, _ MessageBoxIcon.Information) End If End If Catch ex As Exception MessageBox.Show(ex.Message, ex.Source, _ MessageBoxButtons.OK, MessageBoxIcon.Error) End Try
5. Save your project, then press F5 to run it. 6. Within Excel, click the Load Data link, and verify that youve successfully loaded the data. 7. Modify any of the loaded data and click the Update Data hyperlink to send your changes back to SQL Server. 8. Close Excel, but this time dont save the changes made to the workbook. Once back in Visual Studio .NET, press F5 again to start debugging again. 9. Click the Load Data link again, and verify that that your submitted changes show up. 10. Close Excel (saving the workbook, if you like), returning to Visual Studio .NET.
3. Within Excel, click the Load Data link. 4. Modify any of the loaded data and then attempt to close the workbook. You will see an alert indicating that you have changes to be saved. Click Yes to save your changes. 5. When Excel prompts you to save the workbook, select No. 6. Once back in Visual Studio .NET, press F5 again to start debugging again. 7. Click the Load Data link again, and verify that that your changes show up. 8. Close Excel (saving the workbook, if you like), returning to Visual Studio .NET.