The first thing you need to get sorted when moving to SQL Azure is having the ability to get your information out and safe if needs be. When experimenting with MS Azure and for applications that don’t have sensitive information it is nice to have that information available in an easily accessible format. Here are a series of functions that will copy Azure Tables linked to database into local MS Access tables with the prefix ZCOPY.
The starting point in this should be an MS Access database that should be linked to your SQL Azure Database. Only those tables that are linked will be copied. Remember the 2GB limit on Access.
I think I have got all the functions here that are required to make it work and include the complete module at the bottom but first I will breakdown the modules and list describe what each of the functions do.
First create a table to store the list of tables in the Azure Database
Public Function CreateTableT0001AzureTablesGlobal() Dim dbs As Database Set dbs = CurrentDb dbs.Execute "CREATE TABLE T0001AzureTablesGlobal " _ & "(PKID AUTOINCREMENT, " _ & "AzureTableName CHAR CONSTRAINT PKID " _ & "PRIMARY KEY);" End Function
Now Create a Function that will hold the SQL that takes the tables and makes them locally.
Public Function CreateTableT0002SQL() Dim dbs As Database Set dbs = CurrentDb dbs.Execute "CREATE TABLE T0002SQL " _ & "(PKID AUTOINCREMENT, " _ & "SQL MEMO CONSTRAINT PKID " _ & "PRIMARY KEY);" End Function
A function that allows for stepping through the table
Public Function AddByteColumn(TblName As String, FieldName As String) 'Just use byte data type as only going to use this for a flag DoCmd.RunSQL "AlTER TABLE [" & TblName & "] ADD COLUMN " & FieldName & " BYTE;" End Function
Step through the Linked Azure Tables and poupulate table T001 with their names
Public Function CreateandPopulateListofDBOTableNames() 'These will typically be the names of the SQL Server tables this should work both with SQL Server and SQL Azure Dim db As DAO.Database Dim tdf As DAO.TableDef Dim rstList As DAO.Recordset 'Call CreateTableT0001AzureTablesGlobal Set rstList = CurrentDb.OpenRecordset("T0001AzureTablesGlobal") Set db = CurrentDb For Each tdf In db.TableDefs ' ignore system and temporary tables and tables starting with T - personal choice option If Not (tdf.Name Like "MSys*" Or tdf.Name Like "~*" Or tdf.Name Like "T*") Then With rstList .AddNew rstList!AzureTableName = tdf.Name rstList.Update End With End If Next Set tdf = Nothing Set db = Nothing End Function
The next function is required to strip out additional spaces in names
Public Function FindXReplaceY(FixTable As String, FixColumn As String, X As String, Y As String) As Variant Dim strSQL As String strSQL = "UPDATE [" & FixTable & "] SET [" & FixTable & "].[" & FixColumn & "] = REPLACE([" & FixColumn & "]," & Chr$(34) & X & Chr$(34) & "," & Chr$(34) & Y & """);" DoCmd.RunSQL strSQL End Function
We can now write the VBA that will write the make table SQL that once run will put one make table query into the maketableSQL table for each Azure table.
Public Function CreateMakeTableSQL() On Error GoTo Err_CreateMakeTableSQL Dim rstSQL As DAO.Recordset Dim rstSQLx As DAO.Recordset Dim dbc As DAO.Database Dim SQLStringAdd As String Dim LCounter As Long Set dbc = CurrentDb LCounter = 1 While LCounter < 9000 LCounter = LCounter + 1 Set rstSQL = CurrentDb.OpenRecordset("SELECT T0001AzureTablesGlobal.PKID, T0001AzureTablesGlobal.AzureTableName, T0001AzureTablesGlobal.XFLag1 FROM T0001AzureTablesGlobal WHERE (((T0001AzureTablesGlobal.XFLag1) Is Null));") SQLStringAdd = "SELECT * INTO COPY" & rstSQL!AzureTableName & " FROM " & rstSQL!AzureTableName & ";" Set rstSQLx = CurrentDb.OpenRecordset("T0002SQL") With rstSQLx .AddNew rstSQLx!SQL = SQLStringAdd rstSQLx.Update rstSQLx.Close End With With rstSQL rstSQL.Edit rstSQL!XFLag1 = 1 rstSQL.Update rstSQL.MoveNext rstSQL.Close End With Wend Exit_CreateMakeTableSQL: Exit Function Err_CreateMakeTableSQL: Select Case Err.Number Case 3021 Resume Exit_CreateMakeTableSQL Case Else Resume Exit_CreateMakeTableSQL End Select End Function
And finally Run all the queries
Public Function RunQueriesFromTable2(SQLSource As String) DoCmd.SetWarnings False Dim StartTime As Date Dim EndTime As Date Dim rstZ As DAO.Recordset Dim strSQL2 As String StartTime = Now() Set rstZ = CurrentDb.OpenRecordset(SQLSource) Do Until rstZ.EOF strSQL2 = rstZ!SQL DoCmd.RunSQL strSQL2 rstZ.MoveNext Loop DoCmd.SetWarnings True EndTime = Now() MsgBox "Finished ALL SQL queries! Process started at " & StartTime & " and finished at " & EndTime End Function
And a script to pull all of this together
Public Function GetAzureScript() DoCmd.SetWarnings False Call CreateTableT0001AzureTablesGlobal Call CreateandPopulateListofDBOTableNames Call FindXReplaceY("T0001AzureTablesGlobal", "AzureTablename", " ", "") Call FindXReplaceY("T0001AzureTablesGlobal", "AzureTablename", Chr(10), "") Call AddByteColumn("T0001AzureTablesGlobal", "XFLag1") Call CreateTableT0002SQL Call CreateMakeTableSQL Call FindXReplaceY("T0002SQL", "SQL", " ", "") Call FindXReplaceY("T0002SQL", "SQL", Chr(10), "") Call FindXReplaceY("T0002SQL", "SQL", "SELECT*INTOCOPY", "SELECT * INTO ZCOPY") Call FindXReplaceY("T0002SQL", "SQL", "FROM", " FROM ") Call RunQueriesFromTable("T0002SQL") DoCmd.SetWarnings True End Function
The complete module
Option Compare Database Option Explicit Public Function GetAzureScript() DoCmd.SetWarnings False Call CreateTableT0001AzureTablesGlobal Call CreateandPopulateListofDBOTableNames Call FindXReplaceY("T0001AzureTablesGlobal", "AzureTablename", " ", "") Call FindXReplaceY("T0001AzureTablesGlobal", "AzureTablename", Chr(10), "") Call AddByteColumn("T0001AzureTablesGlobal", "XFLag1") Call CreateTableT0002SQL Call CreateMakeTableSQL Call FindXReplaceY("T0002SQL", "SQL", " ", "") Call FindXReplaceY("T0002SQL", "SQL", Chr(10), "") Call FindXReplaceY("T0002SQL", "SQL", "SELECT*INTOCOPY", "SELECT * INTO ZCOPY") Call FindXReplaceY("T0002SQL", "SQL", "FROM", " FROM ") Call RunQueriesFromTable2("T0002SQL") DoCmd.SetWarnings True End Function Public Function CreateandPopulateListofDBOTableNames() 'These will typically be the names of the SQL Server tables this should work both with SQL Server and SQL Azure Dim db As DAO.Database Dim tdf As DAO.TableDef Dim rstList As DAO.Recordset 'Call CreateTableT0001AzureTablesGlobal Set rstList = CurrentDb.OpenRecordset("T0001AzureTablesGlobal") Set db = CurrentDb For Each tdf In db.TableDefs ' ignore system and temporary tables and tables starting with T - personal choice option If Not (tdf.Name Like "MSys*" Or tdf.Name Like "~*" Or tdf.Name Like "T*") Then With rstList .AddNew rstList!AzureTableName = tdf.Name rstList.Update End With End If Next Set tdf = Nothing Set db = Nothing End Function Public Function FindXReplaceY(FixTable As String, FixColumn As String, X As String, Y As String) As Variant Dim strSQL As String strSQL = "UPDATE [" & FixTable & "] SET [" & FixTable & "].[" & FixColumn & "] = REPLACE([" & FixColumn & "]," & Chr$(34) & X & Chr$(34) & "," & Chr$(34) & Y & """);" DoCmd.RunSQL strSQL End Function Public Function CreateTableT0001AzureTablesGlobal() Dim dbs As Database Set dbs = CurrentDb dbs.Execute "CREATE TABLE T0001AzureTablesGlobal " _ & "(PKID AUTOINCREMENT, " _ & "AzureTableName CHAR CONSTRAINT PKID " _ & "PRIMARY KEY);" End Function Public Function CreateTableT0002SQL() Dim dbs As Database Set dbs = CurrentDb dbs.Execute "CREATE TABLE T0002SQL " _ & "(PKID AUTOINCREMENT, " _ & "SQL MEMO CONSTRAINT PKID " _ & "PRIMARY KEY);" End Function Public Function AddByteColumn(TblName As String, FieldName As String) 'Just use byte data type as only going to use this for a flag DoCmd.RunSQL "AlTER TABLE [" & TblName & "] ADD COLUMN " & FieldName & " BYTE;" End Function Public Function CreateMakeTableSQL() On Error GoTo Err_CreateMakeTableSQL Dim rstSQL As DAO.Recordset Dim rstSQLx As DAO.Recordset Dim dbc As DAO.Database Dim SQLStringAdd As String Dim LCounter As Long Set dbc = CurrentDb LCounter = 1 While LCounter < 9000 LCounter = LCounter + 1 Set rstSQL = CurrentDb.OpenRecordset("SELECT T0001AzureTablesGlobal.PKID, T0001AzureTablesGlobal.AzureTableName, T0001AzureTablesGlobal.XFLag1 FROM T0001AzureTablesGlobal WHERE (((T0001AzureTablesGlobal.XFLag1) Is Null));") SQLStringAdd = "SELECT * INTO COPY" & rstSQL!AzureTableName & " FROM " & rstSQL!AzureTableName & ";" Set rstSQLx = CurrentDb.OpenRecordset("T0002SQL") With rstSQLx .AddNew rstSQLx!SQL = SQLStringAdd rstSQLx.Update rstSQLx.Close End With With rstSQL rstSQL.Edit rstSQL!XFLag1 = 1 rstSQL.Update rstSQL.MoveNext rstSQL.Close End With Wend Exit_CreateMakeTableSQL: Exit Function Err_CreateMakeTableSQL: Select Case Err.Number Case 3021 Resume Exit_CreateMakeTableSQL Case Else Resume Exit_CreateMakeTableSQL End Select End Function Public Function RunQueriesFromTable2(SQLSource As String) DoCmd.SetWarnings False Dim StartTime As Date Dim EndTime As Date Dim rstZ As DAO.Recordset Dim strSQL2 As String StartTime = Now() Set rstZ = CurrentDb.OpenRecordset(SQLSource) Do Until rstZ.EOF strSQL2 = rstZ!SQL DoCmd.RunSQL strSQL2 rstZ.MoveNext Loop DoCmd.SetWarnings True EndTime = Now() MsgBox "Finished ALL SQL queries! Process started at " & StartTime & " and finished at " & EndTime End Function