Excel VBA Using MS Access DB Should I close connection? - excel

I'm creating an Excel VBA program for people at my office. The way I intend it to work is each person will have their own "portal", an Excel document where they can interact with the DB with their own user settings. This way there won't be issues with multiple people trying to use an Excel file at the same time.
The thing I'm not sure about is the Access Database I'm setting up. It's a single DB file that everyone can access. Currently the plan is to create the connection this way:
Dim accessFileLoc As String: accessFileLoc = "C:\Users\gmloo\OneDrive\Desktop\Grab Project\GrabDB.accdb"
'create the connection object, and open the connection
Set accessCon = CreateObject("ADODB.connection")
'i HOPE setting the mode like this will allow multiple users to connect to the same
'db at the same time
accessCon.Mode = 16 + 3 'adModeShareDenyNone + adModeShareReadWrite
accessCon.Open "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & accessFileLoc
accessCon is a global Excel VBA variable that is currently designed to hold the connection as long as the Excel program is open. My question is, will this cause problems with other users all Querying the DB file at the same time? Should I be closing the connection for each user while it isnt needed, then re-establish it when they have to do a query? There's probably going to be up to 15 people using their Excel portal at any given time.
Thanks for your help.

You should be fine with multiple users connecting at the same time. However, due to memory and performance issues, I would recommend you close the connection after each query.

Related

How to make a new OLEDB data connection in Excel 365

Looks like a silly question, but Excel 365 defaults to creating a new query type connection when you want to "get data". We are used to creating OLEDB connections to Oracle, SQL server and MS Access databases at work and in previous version of Excel, this was alwas a data connection. Excel 365, defaults to creating a new style Query (Data tab, Get data -> From Other Sources -> From OLEDB).
This new query style does not suit our needs. I haven't found any way to create the old style dataconnection in Excel 365. Can anyone give me pointers how to do this?
Background:
We are sending Excel files with data to customers and we change connection strings and queries using VB Script so as not to send out too much internal information (tables, connection details, credentials). So we update the dataconnection from a VBScript file program where we set connectionstring and sometimes the commandtext.
Differences I see:
In the Query, the connection string is something like "OLEDB:Provider=Microsoft.Mashup.Oledb.1;Data Source = $Workbook$;Location=CURRENT_PERIOD;Extended Properties=""
The commandtext is "select * from [Query1]"
Changing the commandtext here results in an error "[Expression.Error] The import consumables matches no exports. Did you miss a module reference?"
In the older connection style, de connection string is "OLEDB;Provider=MSDASQL.1;DSN=" with commandtext "select * from current_period". We could change the commandtext at will to get different results. We could also change the connection string to include login credentials so the query would run.
Also by changing the connection string you could change the connection to OLEDB connection, ODBC connection or a connection to an MS Access database. Changing the connection string in the new query type connection results in an error and does nog give a different type of connection.
It is just not working for what we do and I can't find a way to create the old style connection.
You need to enable the legacy import wizards.
Go to File > Options > Data. Then check all of the legacy import wizards.
Once these settings have been saved, you will see these options appear under the Data > Get Data menu.

Read MS Access from Excel using Binary.Buffer to avoid errors accessing db in Admin mode

I have an Excel spreadsheet "Report.xlsx" which reads data from MS Access "Database.accdb". Within Report.xlsx, I wrote a simple macro "Macro1" which refreshes the data table in the spreadsheet.
Within MS Access, I am connecting to Excel and launching the macro.
This process fails with the following error in Excel:
DataFormat.Error: The database has been placed in a state by user 'Admin' on machine 'BRNMBL0324' that prevents it from being opened or locked.
Details:
Portal front-end extracts.accdb
Here is the MQuery that fails:
let
Source = Access.Database(File.Contents("Database.accdb"), [CreateNavigationProperties=true]),
#"Table 1" = Source{[Schema="",Item="My database table"]}[Data]
in
#"Table 1"
If I read the database using a Binary.Buffer (per https://social.technet.microsoft.com/Forums/en-US/67852ccf-3c04-42c7-ac5c-6213d4d7b3a2/the-database-has-been-placed-in-a-state-by-user-8216admin8217-on-machine8230-that-prevents?forum=powerquery), the process works:
let
MyDbBinary = Binary.Buffer(File.Contents("Database.accdb")),
Source = Access.Database(MyDbBinary, [CreateNavigationProperties=true]),
#"Table 1" = Source{[Schema="",Item="My database table"]}[Data]
in
#"Table 1"
Since there is only one query in the spreadsheet, I am confident that the issue is not concurrent queries. I closed and reopened the Access db, so I know that the issue is not an unsaved object in MS Access.
Is using Binary.Buffer a robust way of addressing this issue?

Selecting a schema to connect to when connecting over an ODBC connection in Excel's Power Query

So I have a fairly simple query (proof of concept) where I'm able to dynamically pull in data from a database depending on my Excel sheet inputs. For example:
let
Source = Odbc.Query("dsn=Dev 2", "select * #(lf)from job_id JI#(lf)where JI.job_ID = " & Text.From(GetNamedRange("SQLJobInstanceID")) & "#(lf)")
in
Source
Hurray, it works! However, when I was setting up the connection, I needed to log in. Part of the login includes the schema that I wanted to connect to. Username[Schema] is how it's done. Now that I've connected, I'd like to select a different schema to connect to - but I'm not sure how I can either modify the schema, or log out and log back in.
(Also curious if the connection is storing my credentials, which would be problematic, or if other people would need to log in with their credentials)
I believe I can also edit which ODBC connection I'm using by editing the "dsn=Dev 2" portion of the code (Again, will probably turn it into a named range drop down menu.... the challenge becomes dynamically figuring out what ODBC options each user has and pulling those through...)
Thank you

VBA to properly access multi user database

I have an Excel Add-In project that I'm working on which has multiple users accessing a database on the server. Currently all the code works and everything processes correctly as long as only one user is accessing the database at a time. I'm using DAO to access the database and passing an SQL string it to retrieve records using the following lines of code
Set db = OpenDatabase(g400DBPath, , True)
Set rs = db.OpenRecordset(sSQL, dbOpenSnapshot)
This creates an issue where if more than one person attempts to access the database at the same time, only the first person is able to access it. I tried changing the recordset line of code to the following
Set rs = db.OpenRecordset(sSQL, dbOpenSnapshot, , dbOptimistic)
but that gives me the following error: Run-time error '3001: Invalid Argument
How would I go about setting the access to the record set so that multiple users can run the report? The users are not updating any information in the database at all, everything is read only.
Your problem is: a snapshot-type recordset is always read-only. Specifying any edit lock options will throw a run-time error, since snapshot-type recordsets don't do locking.
I can't reproduce the behavior, but you can try the following:
Set db = OpenDatabase(g400DBPath, False, False) 'Read-only can lead to exclusive locks since more specific locks are stored in the DB
Set rs = db.OpenRecordset(sSQL, dbOpenSnapshot, dbReadOnly)
Alternatively, you could try using ADO and disconnected recordsets. DAO doesn't offer that functionality as far as I know.

Excel VBA Connection to MS Access (Read/Write) to Multi User Tables/ Queries

I have got to the end of trying to figure out why I can't get correct settings for multi user read and update to MS Access tables from Excel (Office 2013). So I am hoping someone here can help.
Background - I have an MS Access database that contains all data in tables that is used by an Excel application that runs on each users machine. The .accdb file resides on a shared QNAP NAS. I have designed the system so there is a user list table that is accessed on startup via a form, allowing users to 'login' to the system. When a user is logged in, the intention is to record a Yes/No field in this table to prevent the same user name being used on two different machines accessing the same subset of data.
Now this all works well from one machine or multiple excel instances on one machine.
When I load the excel application on multiple machines, the Yes/No field is inconsistent between the machines, unless I stop the Excel application on the machine and restart. Sometimes I get access errors or database corruption errors in this multi user setup - so I am clearly doing something wrong - but can't figure it out. Help Please!!
The connection from the excel application is done as follows:
' connect to the Access database
Set cn = New ADODB.Connection
With cn
.Provider = "Microsoft.ACE.OLEDB.12.0"
.Mode = adModeShareDenyNone
.CursorLocation = adUseServer
.Open ThisWorkbook.Worksheets("Title").Range("B1") & "cms.accdb"
End With
The recordset is opened in excel as follows (which does not show a user set as logged on another machine in via the yes/no field unless I start the application AFTER they have 'logged in')
Set rs = New ADODB.Recordset
sSQL = "SELECT [access list].* FROM [access list] where [access list].[user] = '" & Me.userlist.Text & "';"
rs.Open sSQL, cn, adOpenDynamic, adLockPessimistic
Application.CalculateUntilAsyncQueriesDone ' not sure I need this????
The test for this user being logged in is:
If rs.Fields("Logged in").Value = -1 Then
fname = rs.Fields("user").Value
rs.Close
cn.Close
Set rs = Nothing
Set cn = Nothing
MsgBox fname & " is already logged in - please select another user or exit"
Else
userid = rs.Fields("user").Value
rs.Close
Set rs = Nothing
sSQL = "Update [access list] Set [access list].[logged in] = '-1' WHERE [access list].[user] = '" & userid & "'"
cn.Execute (sSQL)
MsgBox "Welcome " & userid & "! Starting system for your contracts."
cn.Close
Set cn = Nothing
Unload Me
End If
So what am I doing wrong? I've tried all different ways with little difference. (Note - I am not trying to test race conditions by both logging in to the same user at exactly the same time - a situation that is not of concern - this is just a simple lock out model I'm implementing). I thought what I was doing was keeping record level locking, made sure I could see any other user change to the record in each application on each machine. I'm stumped! Opening MS Access and looking at the database shows the inconsistency - on one machine the user is logged in, on the other the user is not. I'm thinking its how I connect to the access database or some setting in the access database that I haven't got right - but thats just a thought.
One last twist to this - my test environment machines are Apple MacBooks running Win 8.1/ Office 2013 in a VMware Fusion virtual machine. I do not have the environment to test on native Win 8.1 machines at the moment, but this will be the eventual target. Maybe it will work on the target environment, but can't test that yet and as that is the last step, working out any problems with the code in the test environment is my current priority.
Russ
I see this post is old, so you may have moved on already, but thought I would answer in case it helps someone. I have been investigating a similar issue where cursor location and lock type seem to be specified correctly, but I still sometimes get inconsistent read results. I am no expert, but this may have to do with the cache refresh and write delays associated with JET/ACE/Access databases. You may want to play around with the Page Timeout and Flush Transaction Timeout settings and consider using the DBEngine.Idle dbRefreshCache statement before doing a read - although this is a DAO feature.

Resources