How can I programmatically create a DSN? - sql-server

I have an Access Form that uses a linked sql server table as a datasource. I will need to distribute this file to other users soon and I need a way to programmaticly install the DSN to their machines.
This is the process of manually setting up the link:
External Data > More > ODBC Database > Link to data source > Machine data source tab >
press new > user data source > sql server > name=up to you; server= serverName > How should SQL server verify the autheticity of the login ID? With windows NT authentication using the network login ID > Attach database File Name (database name) > choose the table and press ok
That is what I did to access my table but I would like it so that the user can press a button and get access to the table and at the same time be authenticated by using windows NT authentication.
I am having trouble finding a way to write this in access vba code can someone direct me in the right direction?

As a general rule you find MUCH better success by using a DSN less connection. This will eliminate many issues and problems. How to use a DSN less connection is outlined here:
http://www.accessmvp.com/DJSteele/DSNLessLinks.html
And also you do NOT want to store the user name + password in the connection string, but only “log on” one time. Again this saves huge hassles and also means your connection strings and/or DSN does not have to save and expose the user name and password in the actual links.
And this approach means you can have different logons and NOT have to re-link or change existing table links.
The follow shows how to use a cached logon and this thus allows one to have different logons without having to re-link your tables.
https://blogs.office.com/en-us/2011/04/08/power-tip-improve-the-security-of-database-connections/
I highly recommend you adopt both of the above approaches when using linked tables to SQL server.

This question is the first google result for "VBA create DSN", however I do not like the answers since they seem to revolve around touching the registry or otherwise avoiding the use of a DSN. In my case I have a project manager that wants to use a DSN because that is what they are comfortable with and so I could not avoid it. For anyone else struggling with this, I found a very straight forward way to do it elsewhere. Notably starting here.
I used code found there, here and here to cobble this together and put it in the open event of a splash screen form:
Private Declare Function SQLConfigDataSource Lib "ODBCCP32.DLL" _
(ByVal hwndParent As Long, ByVal fRequest As Long, _
ByVal lpszDriver As String, ByVal lpszAttributes As String) As Long
Private Sub Form_Open(Cancel As Integer)
On Error Resume Next
If fDsnExist("DSN=YOUR_DSN_NAME") = True Then
'Do all of your loading or just close this form.
Else
Dim doContinue As Integer
doContinue = MsgBox("There is an issue with the database connection. This can be corrected now or you can reach out to support." _
& vbCrLf & vbCrLf & "Do you want to attempt to correct the issue now?", vbYesNo, "Connection Error")
If doContinue = vbYes Then
Dim vAttributes As String
vAttributes = "DSN=YOUR_DSN_NAME" & Chr(0)
vAttributes = vAttributes & "Description=Self Explnatory" & Chr(0)
vAttributes = vAttributes & "Trusted_Connection=Yes" & Chr(0)
vAttributes = vAttributes & "Server=YOUR_SQL_SERVER_ADDRESS" & Chr(0)
vAttributes = vAttributes & "Database=YOUR_DATABASE_NAME" & Chr(0)
SQLConfigDataSource 0&, 1, "SQL Server", vAttributes
If Err.Number <> 0 Then
MsgBox "The connection could not be restored. Please report this error to support: " & vbCrLf & vbCrLf & Err.Description
Err.Clear
DoCmd.Close acForm, "frmSplash"
DoCmd.Quit acQuitSaveNone
Else
MsgBox "The Connection has been restored.", , "Success"
End If
Else
MsgBox "Please contact support to resolve this issue.", vbCritical + vbOKOnly, "Error"
DoCmd.Close acForm, "frmSplash"
DoCmd.Quit acQuitSaveNone
End If
End If
End Sub
Function fDsnExist(strDsn)
On Error Resume Next
' ------------------------------------------------------
' Declare Variables
' ------------------------------------------------------
Dim objConnection
Dim strReturn
' ------------------------------------------------------
' Create database object
' ------------------------------------------------------
Set objConnection = CreateObject("ADODB.Connection")
objConnection.ConnectionString = strDsn
objConnection.Open
' ------------------------------------------------------
' Check if database is open Correctly
' ------------------------------------------------------
If Err.Number <> 0 Then
strReturn = False
Err.Clear
Else
strReturn = True
' ------------------------------------------------------
' Close database connection
' ------------------------------------------------------
objConnection.Close
End If
Set objConnection = Nothing
' ------------------------------------------------------
' Return database status
' ------------------------------------------------------
fDsnExist = strReturn
End Function
Now when the user opens the access database, the splash form checks for the existence of the DSN and if it is not found, gives the user an option to create it.
You mentioned NT authentication; I use a trusted connection under the assumption that the user is already logged into a domain and has been provided access using those credentials to the SQL server. You may need to modify the DSN connection string in order to prompt for a password and username.

First and foremost, Albert D. Kallal is absolutely correct with his answer. If you can use a DSN-less connection, you should. However, for the sake of answering the question you asked...
ODBC DSN entries are stored in the windows registry. You can add by directly modifying the windows registry. I DO NOT recommend this if you are not familiar with the registry. You can brick a machine if you remove/alter the wrong keys. The particular keys we're looking for are located under Software/ODBC of HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER, depending on whether we're looking for a System or User odbc connection respectively.
My solution is too long and involved to post in it's entirety on Stack Overflow. You can find it on my blog under VBA ODBC DSN Installer complete with class module downloads and examples of how to use them. (Full disclosure, one of them was originally written by Steve McMahon, but I have modified it for use with MS Access.)
The short version is I built a DSN class on top of Mr. McMahon's registry class in order to install DSNs when my MS Access application is started.

Related

Set commandtimeout for linked SQL Tables/Views in Access front end

We have moved some back-end data tables over from a network drive (mbd file) to being on an SQL Server database. Things mostly work great, but if staff are accessing things through a VPN (which slows things down a lot), then we get connection errors when we run reports that retrieve a lot of data. My guess is that I need to set a timeout to a larger value, and I did some research and it seems that I need to set the commandtimeout (or maybe query timeout?).
Below is the VBA code we use to connect the SQL Server tables/views to our Access front end from the SQL Server back end. Am I right that I likely need to specify a commandtimeout? Where in this would we add the commandtimeout (or other timeout) value?
Public Sub CreateSQLLinkedTable(strSourceTableName As String, strNewTableName As String)
'************************************************************************************
'* Create a linked table in the current database from a table in a different SQL Server file.
'* In: *
'* strNewTableName - name of linked table to create *
'* strSourceTableName - name of table in database *
'************************************************************************************
Setup:
Dim tdf As TableDef
Dim strConnect As String, strMsg As String
Dim myDB As Database
' set database vars
Set myDB = CurrentDb
Set tdf = myDB.CreateTableDef(strNewTableName)
MakeConnections:
On Error GoTo OnError
' turn system warnings off
DoCmd.SetWarnings False
' define connect string and source table
' We do not need to specify the username (Uid) and password (Pwd) in this connection
' string, because that information is already cached from the connection to the SQL
' Projects database that we created in CheckSQLConnection() that was run to check connection
' to the database. So here we can have a connection string without the Uid and Pwd.
With tdf
.Connect = "ODBC;Driver={SQL Server};" & _
"server=" & myServer & ";" & _
"database=" & mySQLDB & ";"
.SourceTableName = strSourceTableName
End With
' execute appending the table
myDB.TableDefs.Append tdf
' turn system warnings back on
DoCmd.SetWarnings True
ExitProgram:
' this block of code will run if there are no errors
Exit Sub
OnError:
' this block of code runs if there is an error, per On Error assignment above
' display error message with details
MsgBox "There was an error connecting to the SQL Server data source Projects. Error = " & err & ", Description: " & err.Description
'exit Projects
Call CloseFormsAndQuit
End Sub
There is an ODBC timeout property. Open the query in design view, and go to properties to see it. There is also an (ODBC) query timeout on the current database properties page. You can set it programmatically as well:
Dim objDB As DAO.Database
Set objDB = CurrentDb()
objDB.QueryTimeout = 120
http://www.geeksengine.com/article/how-to-change-timeout-value-for-access-sql.html
Also check the server configuration. There is a query timeout on server side.

Microsoft Access Checkbox with SQL Backend Does Not Update

I've been researching it and have found many similar cases... but none exactly the same. I've tried a lot of different resolutions in the previous cases mentioned and none of them fixed this one.
I just recently did a SQL Server Migration and am now troubleshooting the issues that have sprung up with the new SQL back end. This is the last one that I can not figure out:
I have a split form with a check box control, bound to a SQL Server View through a DSN-Less connection. Before the migration the Bound Access Query could not be updated... so I programatically updated the forms checkboxes through VBA using two different methods:
Was a check all/ check none checkbox which when clicked checked or unchecked all of the checkboxes in the datasheet.
Gave the ability for the user to check or uncheck each individual checkbox by using the checkboxes Mouse_Down Event.
Here is the code for each of the two methods:
' Check All/ Check None
Dim rsSelect As DAO.Recordset
Dim rsUpdate As DAO.Recordset
Dim SQL As String
Dim CurrDb As Database
Dim currFilter As String
On Error GoTo chkSelect_Click_Error
' Capture current filter
If Me.FilterOn Then currFilter = Me.Filter
Set rsSelect = Me.RecordsetClone
Set CurrDb = CurrentDb
rsSelect.MoveFirst
Do While Not rsSelect.EOF
SQL = "SELECT * FROM tblTimesheet WHERE [TimesheetID] = " & rsSelect("TimesheetID")
Set rsUpdate = CurrDb.OpenRecordset(SQL, dbOpenDynaset, dbSeeChanges)
If Not rsUpdate.EOF Then
If Me.chkSelect Then
With rsUpdate
.Edit
rsUpdate("TimesheetSelect") = True
.Update
End With
Else
With rsUpdate
.Edit
rsUpdate("TimesheetSelect") = False
.Update
End With
End If
End If
rsSelect.MoveNext
Loop
rsUpdate.Close
rsSelect.Close
Me.Requery
If currFilter > "" Then
Me.Filter = currFilter
Me.FilterOn = True
End If
If Me.chkSelect Then
Me.lblSelect.Caption = "Select None"
Else
Me.lblSelect.Caption = "Select All"
End If
On Error GoTo 0
Exit Sub
chkSelect_Click_Error:
MsgBox "Error " & Err.Number & " (" & Err.Description & ") in procedure chkSelect_Click of VBA Document Form_frmTimesheetSummary"
And Secondly:
' Check/ Uncheck Individual Checkbox
Dim rsUpdate As DAO.Recordset
Dim SQL As String
Dim CurrDb As Database
Dim currFilter As String
' Capture current filter
If Me.FilterOn Then currFilter = Me.Filter
Set CurrDb = CurrentDb
SQL = "SELECT * FROM tblTimesheet WHERE [TimesheetID] = " & Me.TimesheetID
Set rsUpdate = CurrDb.OpenRecordset(SQL, dbOpenDynaset, dbSeeChanges)
If Not rsUpdate.EOF Then
If Me.TimesheetSelect Then
With rsUpdate
.Edit
rsUpdate("TimesheetSelect") = False
.Update
End With
Else
With rsUpdate
.Edit
rsUpdate("TimesheetSelect") = True
.Update
End With
End If
End If
rsUpdate.Close
Me.Form.Requery
'Me.Repaint
Me.Refresh
If currFilter > "" Then
Me.Filter = currFilter
Me.FilterOn = True
End If
Both of these procedures worked with an Access back end... but the "Check Individual" procedure refuses to work now. When I check a checkbox it does update the SQL Backend... but the control itself refuses to update the new status... I of course have tried Requery, but also Repaint and Refresh and it refuses to update unless I completely close the form and reopen it again.
The real kicker in all this is that the Check All method still works! I've spent hours on this and am hoping to get some fresh eyes on it because it should be working if the backend is updating!!
ADDITIONAL NOTES ADDED LATER: In response to some of the great reasoning below I feel I should include this additional notes:
I am using SQL Server 2012 and the SQL Server Native Client 11.0 Driver for my connection string.
I am using Microsoft Access 2010 32 bit
The SQL Server field is a bit I've removed all nulls and set allow nulls to 'no' with a default of 0
Some things come to mind:
1) You can replace the whole rsUpdate construction in the second procedure by this:
SQL = "UPDATE tblTimesheet SET TimesheetSelect = " & _
IIf(Me.TimesheetSelect, "0", "-1") & _
" WHERE TimesheetID = " & Me.TimesheetID
CurrDb.Execute SQL, dbSeeChanges
It depends on your TimesheetSelect datatype whether you should use "-1" or "1".
2) Me.Form.Requery should be Me.Requery.
3) If it still doesn't work, adding a TIMESTAMP column to tblTimesheet might help Access recognize that the record was changed. This is generally a good thing to have, but shouldn't be necessary.
Recommended reading: https://stackoverflow.com/a/2861581/3820271
tblTimesheet does have a primary key, doesn't it?
If Andre's suggestions don't solve it, instead of Me.Requery, try resetting the form's recordsource. Me.RecordSource = .
You don't say what version of SQL Server you are using or which ODBC driver. Make sure you are using the correct ODBC Driver for your version of SQL Server and not the default 'SQL Server' driver.
Thanks to all who posted... the answer that ended working for me in this case was ditching the split form... I had heard it suggested that split forms can be problematic at times so redesigned the form in a standard Parent/ Subform setup which completely resolved the issue.

Create database in SQL Server (only once) using VBA Excel

I would like to create a database in SQL server using VBA (Excel) just the first time that I will run the code. So the second time I run the code, the database will exist, and it will not create another one.
#abarisone
`Public Sub CreateDBTable()
Dim dbConnectStr As String
Dim Catalog As Object
Dim cnt As ADODB.Connection
Dim dbName As String
Dim tblName As String, ServerName As String, UserID As String, pw As String
tblName = shControl.Range("B5") 'Table Name
ServerName = "SERVICESWS15" 'Enter Server Name or IP
dbName = shControl.Range("B4") 'Enter Database Name
UserID = "" 'Leave blank for Windows Authentification
pw = "" 'Leave blank for Windows Authentification
dbConnectStr = "Provider=SQLOLEDB;Data Source=" & ServerName & ";Initial Catalog=" & dbName & ";User Id=" & UserID & ";Password=" & pw & ";"
Set Catalog = CreateObject("ADOX.Catalog")
Catalog.Create dbConnectStr
Set Catalog = Nothing
Set cnt = New ADODB.Connection
With cnt
.Open dbConnectStr
.Execute "CREATE TABLE " & tblName & " (KEY nvarchar(100) NOT NULL, " & _
"Date nvarchar(100) NOT NULL, " & _
"PRIMARY KEY (KEY));"
End With
Set cnt = Nothing
End Sub
`
There is an error in this line:
Catalog.Create dbConnectStr
Error: No such interface supported
It's not very complicated. First make sure that you are referring to the appropriate ADO library like here on the screenshot.
Then your have certain building blocks you will have to use: first make a Connection object (with a connection string), then make a Command object, and last but not least use the ExecuteNonQuery method of Command on your connection object. It does what the name says: executes an SQL command without having a RecordSet as a return object. See examples in the documentation starting from here.
I have not tried it before, but for this to happen without error, you will probably have to set your connection string to the system database called "Master" if working on MS SQL Server.
Of course, the SQL commands you will have to execute are (1) check if the database exists, (2) create db and tables if not.
Then you can create your "normal" Connection object to your database.
WARNING: to be able to create a database, your technical user defined in the VBA script must have high (system admin) privileges which is definitely a HUGE RISK even if you protect your excel. If it's not a sandbox environment, DO NOT DO IT!

Keeping UID and PWD out of an ADO connection string in an ODBC DSN-less Database and a DAO cached connection?

I have used Ben Clothier's suggestion from his Office Blog Power Tip (http://blogs.office.com/2011/04/08/power-tip-improve-the-security-of-database-connections/) to create a DSN-less connection with cached credentials so that users' UID and PWD aren't saved, or required multiple times, when working in the Access interface. Have others done this? If so, what has been your approach when you need to use an ADO connection instead of DOA to reach SQL from Access via VBA? How do you open a adodb connection without having to provide the User ID and Password again, or having to put it in the code?
(I'm using Access 2013 frontend, SQL 2008 R2 backend, SQL Server Security)
Thanks in advance!
My Cached Connection code works like this:
Public Function InitConnect(strUserName As String, strPassword As String) As Boolean
' Description: Is called in the application’s startup
' to ensure that Access has a cached connection
' for all other ODBC objects’ use.
Dim dbs As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset
Dim strConnection As String
strConnection = "ODBC;DRIVER=sql server;" & _
"SERVER=******;" & _
"APP=Microsoft Office 2010;" & _
"DATABASE=******;" & _
"Network=DBMSSOCN;"
Set dbs = DBEngine(0)(0)
Set qdf = dbs.CreateQueryDef("")
With qdf
.Connect = strConnection & _
"UID=" & strUserName & ";" & _
"PWD=" & strPassword & ";"
.SQL = "Select Current_User;"
Set rst = qdf.OpenRecordset(dbOpenSnapshot, dbSQLPassThrough)
End With
InitConnect = True
ExitProcedure:
On Error Resume Next
Set rst = Nothing
Set qdf = Nothing
Set dbs = Nothing
Exit Function
End Function
Then when I need to access data I can do this (Note the UID and PWD are not required):
Dim dbs As DAO.Database
Set dbs = OpenDatabase("", False, False, "ODBC;DRIVER=sql server;SERVER=*****;APP=Microsoft Office 2010;DATABASE=*****;Network=DBMSSOCN")
I can also set the ODBC connection to pass-through queries as well in Access or VBA. But these connections work only when the connection string is IDENTICAL to what was originally used in my Cached Connection code. So, when I need an ADODB connection (as it seems sometimes ADO is needed?), the string obviously isn't going to be identical.
For Example:
Dim cn As New ADODB.Connection
cn.Open "Provider = sqloledb;Data Source=*same as "SERVER"*;Initial Catalog=*same as "DATABASE"*;User Id=****;Password=****"
This type of connection only works if I supply a User Id and Password. How can I write it so that I don't need them? ~Thanks!
Although ACCESS has some weak points regarding security, you can do few things to minimize the risks. One of them would be compile the DB to ACCDE. This way VBA is compiled and not visible.
You can create a public function that returns a string
Public Function GET_CONNECTION_STRING() as STRING
' construct your connection string here with server name and password
GET_CONNECTION_STRING = "DRIVER={" & Driver & "};PORT=" & mPort & ";DATABASE=" & mDatabase & ";SERVER={" & mServer & "};UID=" & mUser & ";PWD={" & mPassword & "};"
End Function
then create an AutoExe macro that runs when the application is opened.
in your AutoExe perform refreshing links to your linked tables. something similar to what you have.
For Each tdf In db.TableDefs
If tdf.connect <> vbNullString Then
tdf.connect = GET_CONNECTION_STRING & ";TABLE=" & tdf.name
tdf.RefreshLink
End If
Next tdf
you can do the same for existing pass through queries:
For Each myQuerydef In MyDB.QueryDefs
If Left(myQuerydef.connect, 4) = "ODBC" Then
myQuerydef.connect = "ODBC;" & GET_CONNECTION_STRING
myQuerydef.Close
End If
Next
in addition you can have some other public functions to get current logged in username.
something like
public function getCrruserID() as int
'check your public variable crr_user_id if its empty redirect to login
if nz(crr_user_id,0) = 0 then
'go to login and save the user id after successful login
else
getCrruserID = crr_user_id
end if
end function
use simple DAO to execute sql code like
dim db as DAO.Database
set db = currentdb
dim rs as Dao.Recordset
set rs = db.openrecordset("select something from your linked table")
or
db.execute "update command", dbfailonerror
to your last question. if you save something in memory it will be destroyed once your application is closed.
EDIT:
if you have more than 50 linked tables it might be not a good idea to refresh them at every startup. Instead you can create a Local table containing your [local_Appversion, isFreshInstall] and some other variables as per your need. Every time your user receives an update the freshInstall will be true and code your App to connect and refresh all tables. (just to make sure client will get uninterrupted connection)
so in your autoExe code: if its freshInstall then
connect and refreshlinks if not just set the connectionString. (usually a splash screen after login to perform this action)
After successful connection just update the local isFreshInstall value to false for a quicker start next time.
you can also have a dedicated menu where user can click and refresh links manually.(in case if the connection get dropped)
something like
if your organisation has a domain you can allow trusted connection using windows login name
good luck.

What's the fastest way to check the availability of a SQL Server server?

I have an MS Access program in use in multiple locations. It connects to MS SQL Server tables, but the server name is different in each location. I am looking for the fastest way to test for the existence of a server. The code I am currently using looks like this:
ShellWait "sc \\" & ServerName & " qdescription MSSQLSERVER > " & Qt(fn)
FNum = FreeFile()
Open fn For Input As #FNum
Line Input #FNum, Result
Close #FNum
Kill fn
If InStr(Result, "SUCCESS") Then ...
ShellWait: executes a shell command and waits for it to finish
Qt: wraps a string in double quotes
fn: temporary filename variable
I run the above code against a list of server names (of which only one is normally available). The code takes about one second if the server is available and takes about 8 seconds for each server that is unavailable. I'd like to get both of these lower, if possible, but especially the fail case as this one happens most often.
You could try to create an ADO connection and set the timeout to some low value, e.g. (untested):
Dim cn As ADODB.Connection
Set cn = New ADODB.Connection
cn.ConnectionTimeout = 4 ' Wait at most 4 seconds for connection
cn.ConnectionString = "Provider=SQLOLEDB.1;Data Source=" & ServerName & ";Integrated Security=SSPI"
On Error Resume Next
cn.Open
If Err.Number > 0 Then
...
Else
cn.Close
...
End If
On Error Goto 0 ' replace 0 with previously used error handler
I apologize if I am out of line since I am new here, but I wanted to make a suggestion. You can actually capture the output of shelled commands without using an intermediate text file using windows api. I created a small class file that wraps this up cleanly (link).
Using this you can refactor the code to this and not have to worry about the added headache of reading files.
Function SQLServerDBExists(ServerName As String, DbName As String) As Boolean
Dim Result As String
Dim cls as new clsRunApp
On Error GoTo Err_SQLServerDBExists
'Check for existence of the server
Result = cls.RunAppWait_CaptureOutput("nslookup " & ServerName)
If InStr(Result, "Non-existent domain") Then
SQLServerDBExists = False
GoTo Exit_SQLServerDBExists
End If
Result = cls.RunAppWait_CaptureOutput("sc \\" & ServerName & " qdescription MSSQLSERVER")
If InStr(Result, "SUCCESS") Then
With PassThru("SELECT Name FROM sysdatabases " & _
"WHERE Name='" & DbName & "'", "master", ServerName)
SQLServerDBExists = (Not .EOF)
End With
End If
Exit_SQLServerDBExists:
Exit Function
Err_SQLServerDBExists:
LogError Err.Number, Err.Description, "SQLServerDBExists", "AttachToSQL", , , Erl
Resume Exit_SQLServerDBExists
End Function
The solution I eventually settled on was to use nslookup.exe as a precursor to my sc.exe command. If the SQL Server server does not exist, nslookup tells me so immediately. Making this change cut down the time it took to fail on a SQL Server lookup from about 8 seconds to well under 1 second. The success case is actually slightly longer, but not noticeable. For those who may be interested, here is my final solution (hopefully the purpose of my personal functions [ShellWait, Qt, PassThru, LogError] will be obvious):
UPDATE: I've updated the function to incorporate dmaruca's clsRunApp (my new favorite class module) and the issue raised by Philippe concerning working in disconnected mode. The result is much better than I originally posted and I'd like to thank both of them for their contributions. Here's the function as it stands now:
Function SQLServerDBExists(ComputerName As String, DbName As String) As Boolean
Const LocalHost = "127.0.0.1"
Dim Result As String, RunApp As New clsRunApp
On Error GoTo Err_SQLServerDBExists
If ComputerName <> LocalHost And _
ComputerName <> "." And _
ComputerName <> Environ("COMPUTERNAME") Then
'Check for existence of the server using Name Server Lookup'
Result = RunApp.RunAppWait_CaptureOutput("nslookup " & ComputerName)
If InStr(Result, "Non-existent domain") Or _
InStr(Result, "Default servers are not available") Then
SQLServerDBExists = False
GoTo Exit_SQLServerDBExists
End If
End If
Result = RunApp.RunAppWait_CaptureOutput("sc \\" & ComputerName & " qdescription MSSQLSERVER")
If InStr(Result, "SUCCESS") Then
With PassThru("SELECT Name FROM sysdatabases " & _
"WHERE Name='" & DbName & "'", "master", ComputerName)
SQLServerDBExists = (Not .EOF)
End With
End If
Exit_SQLServerDBExists:
Exit Function
Err_SQLServerDBExists:
LogError Err.Number, Err.Description, "SQLServerDBExists", "AttachToSQL"
Resume Exit_SQLServerDBExists
End Function
Note: I realize Environ("COMPUTERNAME") is not a 100% reliable way of determining the computer's name, so feel free to replace that with your own code if you want. I think the lazy approach is sufficient for its purpose here.
The way I've done this (in the distant past) was to use linked tables and have a User form that allows a server to be one-off selected at runtime. Alternatively, you would place the server name in a config file and dynamically create the connection string using it.
telnet servername 1433
The solution proposed here works great in specific conditions, where the computer is networked and a dns server is available. If your application is supposed to work in both connected (where you can connect to one of the 'main' servers) and disconnected mode (where you connect to your local copy of the database), this solution will not do it.
Our generic, efficient but (I must admit) not-so-smart solution is until now to have a client-side connection table (in fact xml files - one per connection - in the app folder) and let the user choose the connection at startup. depending on the user, the place(s) he works in, and his ability to work off-line, we can choose which xml-connection strings to install on his computer.
Our idea is (when we'll have time) to use the ip address of the computer to identify/calculate the 'best' database server available: if computer is not networked, connection will be set to 'localhost'. Otherwise, connection will be built 'on the fly', on a network where database servers are given a predefinite ip suffix. Thus, when a computer's ip is aaa.bbb.ccc.ddd, the machine will know it has to connect to aaa.bbb.120.132, where 120.132 is the predefined database server suffix.

Resources