Option Compare Database
Public Function LinkAllTables(Server As Variant, Database As Variant, _
OverwriteIfExists As Boolean, _
Optional Schema As Variant)
If IsMissing(Schema) = True Then Schema = "dbo"
On Error GoTo Error_Handler
'Usage Example: Call linkalltables("SQL01","SQLDB", true, "HR")
' (link all tables in database "SQLDB" on SQL Server Instance SQO01,
' in the 'dbo' and 'HR' schema's overwriting any existing linked tables.
'This will also update the link if the underlying table definition has been modified.
Dim rsTableList As New ADODB.Recordset
Dim sqlTableList As String
sqlTableList = "SELECT [TABLE_SCHEMA] + '.' + [TABLE_NAME] as TableName"
sqlTableList = sqlTableList + " FROM [INFORMATION_SCHEMA].[TABLES]"
sqlTableList = sqlTableList + " INNER JOIN [sys].[all_objects]"
sqlTableList = sqlTableList + " ON [INFORMATION_SCHEMA].[TABLES].TABLE_NAME = [sys].[all_objects].[name]"
sqlTableList = sqlTableList + " WHERE [sys].[all_objects].[type]=N'U' AND [sys].[all_objects].[is_ms_shipped]<>1"
rsTableList.Open sqlTableList, BuildNativeSQLConnectionString(Server, Database)
' If rsTableList.EOF Then
' Debug.Print "SQL Native Client: No Tables Found"
' Else
' rsTableList.Open sqlTableList, BuildSQLConnectionString(Server, Database)
' If rsTableList.EOF Then
' Debug.Print "SQL Client: No Tables Found"
' End If
' End If
Function_Continue:
Dim arrSchema As Variant
While Not rsTableList.EOF
arrSchema = Split(rsTableList("TableName"), ".", , vbTextCompare)
Select Case LCase(arrSchema(0))
Case "common"
If LinkTable(arrSchema(1), Server, Database, rsTableList("TableName"), OverwriteIfExists) Then
' Debug.Print "Linking common table " & rsTableList("TableName")
End If
Case LCase(Schema)
If LinkTable(arrSchema(1), Server, Database, rsTableList("TableName"), OverwriteIfExists) Then
' Debug.Print "Linking schema table " & rsTableList("TableName")
End If
Case Else
'Skip
End Select
rsTableList.MoveNext
Wend
Error_Handler:
If Err.Number = -2147467259 Then
rsTableList.Open sqlTableList, BuildSQLConnectionString(Server, Database)
GoTo Function_Continue
End If
GoTo Function_Quit
Function_End:
On Error GoTo Function_Quit
rsTableList.Close
GoTo Function_Quit
Function_Quit:
Set rsTableList = Nothing
End Function
Function LinkTable(LinkedTableAlias As Variant, Server As Variant, Database As Variant, SourceTableName As Variant, OverwriteIfExists As Boolean)
On Error GoTo Error_Handler
'This method will also update the link if the underlying table definition has been modified.
'The overwrite parameter will cause it to re-map/refresh the link for LinktedTable Alias, but only if it was already a linked table.
' it will not overwrite an existing query or local table with the name specified in LinkedTableAlias.
'Links to a SQL Server table without the need to set up a DSN in the ODBC Console.
Dim dbsCurrent As Database
Dim tdfLinked As TableDef
' Open a database to which a linked table can be appended.
Set dbsCurrent = CurrentDb()
'Check for and deal with the scenario of the table alias already existing
If TableNameInUse(LinkedTableAlias) Then
If (Not OverwriteIfExists) Then
Debug.Print "Can't use name '" + LinkedTableAlias + "' because it would overwrite existing table."
Exit Function
End If
'delete existing table, but only if it is a linked table
If IsLinkedTable(LinkedTableAlias) Then
dbsCurrent.TableDefs.Delete LinkedTableAlias
dbsCurrent.TableDefs.Refresh
Else
Debug.Print "Can't use name '" + LinkedTableAlias + "' because it would overwrite an existing query or local table."
Exit Function
End If
End If
'Create a linked table
Set tdfLinked = dbsCurrent.CreateTableDef(LinkedTableAlias)
tdfLinked.SourceTableName = SourceTableName
tdfLinked.Connect = "ODBC;" & BuildNativeSQLConnectionString(Server, Database)
Function_Continue:
dbsCurrent.TableDefs.Append tdfLinked
GoTo Function_End:
Error_Handler:
' Debug.Print "ErrorNumber: " & Err.Number & vbCrLf & "ErrorDesc: " & Err.Description & vbCrLf & "ErrorSource: " & Err.Source
Select Case (Err.Number)
Case (3151)
Err.Clear
tdfLinked.Connect = "ODBC;" & BuildSQLConnectionString(Server, Database)
GoTo Function_Continue
Case (-2147467259)
Err.Clear
tdfLinked.Connect = "ODBC;" & BuildSQLConnectionString(Server, Database)
GoTo Function_Continue
Case (3626) 'too many indexes on source table for Access
Err.Clear
On Error GoTo 0
If LinkTable(LinkedTableAlias, Server, Database, "vw" & SourceTableName, OverwriteIfExists) Then
Debug.Print "Can't link directly to table '" + SourceTableName + "' because it contains too many indexes for Access to handle. Linked to view '" & "vw" & SourceTableName & "' instead."
LinkTable = True
Else
Debug.Print "Can't link table '" + SourceTableName + "' because it contains too many indexes for Access to handle. Create a view named '" & "vw" & SourceTableName & "' that selects all rows/columns from '" & SourceTableName & "' and try again to circumvent this."
LinkTable = False
Exit Function
End If
End Select
Function_End:
tdfLinked.RefreshLink
LinkTable = True
GoTo Function_Quit
Function_Quit:
Set tdfLinked = Nothing
End Function
Function BuildSQLConnectionString(Server As Variant, DBName As Variant) As String
BuildSQLConnectionString = "Driver={SQL Server};Server=" & Server & _
";APP=" & Application.CurrentDb.Properties("AppTitle").Value & _
";Database=" & DBName & ";TRUSTED_CONNECTION=yes;"
End Function
Function BuildNativeSQLConnectionString(Server As Variant, DBName As Variant) As String
BuildNativeSQLConnectionString = "Driver={SQL Server Native Client 10.0};Server=" & Server & _
";APP=" & Application.CurrentDb.Properties("AppTitle").Value & _
";Database=" & DBName & ";TRUSTED_CONNECTION=yes;"
End Function
Function TableNameInUse(TableName As Variant) As Boolean
'check for local tables, linked tables and queries (they all share the same namespace)
TableNameInUse = DCount("*", "MSYSObjects", "(Type = 4 or type=1 or type=5) AND [Name]='" & TableName & "'") > 0
End Function
Function IsLinkedTable(TableName As Variant) As Boolean
IsLinkedTable = DCount("*", "MSYSObjects", "(Type = 4) AND [Name]='" & TableName & "'") > 0
End Function
Public Function DeleteODBCTableNames(Optional stLocalTableName As String)
On Error GoTo Err_DeleteODBCTableNames
Dim dbs As Database, tdf As TableDef, i As Integer
Set dbs = CurrentDb
If Len(stLocalTableName) = 0 Then
For i = dbs.TableDefs.Count - 1 To 0 Step -1
Set tdf = dbs.TableDefs(i)
If (tdf.Attributes And dbAttachedODBC) Then
If tdf.Name = "R2IMAGE" Then
' Debug.Print "Skipped Table:" & vbTab & tdf.Name
Else
' Debug.Print "Linked Table:" & vbTab & tdf.Name
dbs.TableDefs.Delete (tdf.Name)
End If
End If
Next i
Else
' Debug.Print "Local Table: " & vbTab & stLocalTableName
dbs.TableDefs.Delete (stLocalTableName)
End If
dbs.Close
Set dbs = Nothing
Exit_DeleteODBCTableNames:
Exit Function
Err_DeleteODBCTableNames:
MsgBox ("Error # " & Str(Err.Number) & " was generated by " & Err.Source & Chr(13) & Err.Description)
Resume Exit_DeleteODBCTableNames
End Function