简体   繁体   English

为多个用户和文件设置从Excel到Access的VBA ADO连接的正确方法是什么?

[英]What is correct way to set up VBA ADO connection from Excel to Access for multiple users and files?

I have several excel files that are used for entering data. 我有几个用于输入数据的excel文件。 Files are identical in functionality, one for each service center of ours. 文件功能相同,一个用于我们的每个服务中心。 In the form there is button that launches a macro which transforms data to table format on another sheet which is then later uploaded to Access db. 在窗体中有一个按钮,用于启动一个宏,该宏将数据转换为另一个工作表上的表格格式,然后将其上载到Access数据库。

Everything worked fine on my own computer. 一切都在我自己的电脑上运行良好。 Adding new rows, updating existing rows and deleting existing roles. 添加新行,更新现有行和删除现有角色。 I had used early binding which lead to problems when I moved files to our network drive. 我使用早期绑定,当我将文件移动到我们的网络驱动器时导致问题。 I managed to convert files to late binding but then other problems arose. 我设法将文件转换为后期绑定,但随后出现了其他问题。

Most of the time, uploading to Access isn't working, especially when multiple users try to do stuff at the same time. 大多数情况下,上传到Access无法正常工作,尤其是当多个用户尝试同时执行操作时。 Most common error code is that I am not using updateable query or that this method doesn't support backwards scrolling. 最常见的错误代码是我没有使用可更新的查询,或者此方法不支持向后滚动。 I sorry for not reporting actual error codes, but I can't replicate them at the moment. 我很抱歉没有报告实际的错误代码,但我现在无法复制它们。

My connection code is as follows, it is bit of a mix of copy paste code from different examples. 我的连接代码如下,它是来自不同示例的复制粘贴代码的混合。

Opening the connection and other prestuff 打开连接和其他预制件

Sub excel2access()

Const adUseClient = 3  
Const adUseServer = 2
Const adLockOptimistic = 3
Const adOpenKeyset = 1
Const adOpenDynamic = 2

Dim oConn As Object
Dim cmd As Object
Dim rs As Object
Dim r As Long
Dim criteria As String
Dim Rng As Range

Set oConn = CreateObject("ADODB.Connection")
Set cmd = CreateObject("ADODB.Command")

oConn.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
        "Data Source= '" & Range("dbpath").Value & "\" & Range("dbfile").Value & "' ;"

Set rs = CreateObject("ADODB.Recordset")
rs.CursorLocation = adUseClient
rs.CursorType = adOpenStatic
rs.LockType = adLockOptimistic
rs.Open "Select * from need_rows WHERE service_center = '" & Range("scenter_name").Value & "'", oConn

r = 2 ' the start row in the worksheet

Sheets("data").Select

This following bit looks through data in excel sheet and tries to find match from recordset found for that service center. 以下位查看excel表中的数据,并尝试从该服务中心找到的记录集中查找匹配项。 If match is not found new record is created and if match is found the old record is updated. 如果未找到匹配,则创建新记录,如果找到匹配,则更新旧记录。

Do While Len(Range("A" & r).Formula) > 0
    With rs
        criteria = Range("D" & r).Value
        .Find "identifier='" & criteria & "'"
        If (.EOF = True) Or (.BOF = True) Then
            .AddNew ' create a new record
            .Fields("service_center") = Range("scenter_name").Value
            .Fields("product_id") = Range("A" & r).Value
            .Fields("quantity") = Range("B" & r).Value
            .Fields("use_date") = Range("C" & r).Value
            .Fields("identifier") = Range("D" & r).Value
            .Fields("file_type") = Range("file_type").Value
            .Fields("use_type") = Range("E" & r).Value
            .Fields("updated_at") = Now
            .Update             
        Else
            If .Fields("quantity") <> Range("B" & r).Value Then
                .Fields("quantity") = Range("B" & r).Value
                .Fields("updated_at") = Now
                .Update ' stores the new record
            End If                      
        End If
        .MoveFirst 
    End With
    r = r + 1 
Loop

rs.Close
Set rs = Nothing
Set oConn = Nothing

MsgBox "Confirmation message"
End Sub

Edit: Based on link by barrowc I changed cursor type to adOpenStatic. 编辑:根据barrowc的链接,我将光标类型更改为adOpenStatic。 I made a test with several users trying to upload data at the same time and everything worked perfectly. 我与几个试图同时上传数据的用户进行了测试,一切都运行良好。 Until one user stayed in the file and spent quite a while editing data there and then tried to upload data to db and got following error message: https://dl.dropbox.com/u/3815482/vba_error.jpg 直到一个用户留在文件中并花了很长时间在那里编辑数据,然后尝试将数据上传到数据库并得到以下错误消息: https //dl.dropbox.com/u/3815482/vba_error.jpg

Again, I am back where I started from. 再一次,我回到了我的起点。

Also, I am open to feedback on my code in general as well. 此外,我也欢迎对我的代码提出反馈意见。

I am using Office 2010. 我正在使用Office 2010。

Am I doing it wrong? 我做错了吗? All help is appreciated. 所有帮助表示赞赏。

sounds to me like Jet isn't reliable enough for your environment. 听起来像Jet对你的环境来说不够可靠。 I frequently use SQL Server / Access Data Projects to consolidate information from multiple spreadsheets into a single database backend that doesn't barf when you add a half dozen users. 我经常使用SQL Server / Access数据项目将来自多个电子表格的信息合并到一个数据库后端,当您添加六个用户时,该后端不会进行barf。

You are going to have a lot of issues with the database being locked by other users. 您将遇到很多其他用户锁定数据库的问题。 This is for several reasons: 这有几个原因:

  • From what I can see you are not handling errors. 从我可以看到你没有处理错误。 Therefore if your script errors half way through the connection will be left open thus causing lock problems. 因此,如果您的脚本错误中途通过连接将保持打开状态,从而导致锁定问题。
  • By the looks of this, the macros could potentially keep the connection open for a decent amount of time (assuming no errors). 通过这种看起来,宏可能会保持连接打开一段相当长的时间(假设没有错误)。

Having created a lot of macros connecting to an MS Access database I can tell you straight up. 创建了许多连接到MS Access数据库的宏后,我可以直接告诉你。 You are going to have a lot of connection issues where the database is being locked by spreadsheets that someone has left open all day/night due to things such as not handling unexpected errors (the connection never closes). 您将遇到许多连接问题,其中数据库被电子表格锁定,因为诸如不处理意外错误(连接永远不会关闭)之类的事情,某人一整天都在打开。

Even once you fix the problems all you need is ONE person to be using the spreadsheet with the old code and they will continue to lock the database. 即使您解决了问题,您只需要一个人使用带有旧代码的电子表格,他们就会继续锁定数据库。

One massive problem is that if someone connects to the database when its already open by someone else I believe they inherit the connection type of the already opened database resulting in a daisy chain of write locks. 一个大问题是,如果有人在数据库已经由其他人打开时连接到数据库,我相信他们继承了已经打开的数据库的连接类型,导致了一个菊花链写锁。 You then need to make sure all connections are severed in order to reset the connection. 然后,您需要确保切断所有连接以重置连接。

You have also not shown us how the data is put into the spreadsheet in the first place. 您还没有向我们展示如何将数据放入电子表格中。 Perhaps you are not correctly closing the connection and that could potentially be the reason why sometimes the database is locked. 也许您没有正确关闭连接,这可能是有时数据库被锁定的原因。

There are many different things you could try to get around this: 您可以尝试解决许多不同的问题:

  • Easiest would be to use MS Access Front End + MS Access Back End. 最简单的方法是使用MS Access前端+ MS Access后端。
  • Instead of pressing this button and uploading the data through connection strings you could make it save the file in a folder which would then be processed by an ms access database that is sitting there watching the folder. 您可以将文件保存在一个文件夹中,而不是按下此按钮并通过连接字符串上传数据,然后该文件夹将由坐在那里观看文件夹的ms访问数据库处理。 This would mean that you upload script would be written in MS Access and just be processing the files. 这意味着您上传的脚本将在MS Access中编写,只是处理文件。 Wouldn't be as instantaneous as your current approach but all write connections would be coming from the same machine/user in this circumstance. 不会像您当前的方法那样瞬间完成,但在这种情况下,所有写连接都将来自同一台机器/用户。
  • Persist with the current method: eventually you may get it to a stable state but it will be a lot of frustration and effort as determining the reason for a lock may not always be easy. 坚持使用当前的方法:最终你可能会把它变成一个稳定的状态,但是由于确定锁定的原因并不总是那么容易,这将是一个很大的挫折和努力。 You could at least look at who has the file locked at the time and work from there but as mentioned earlier they may not have been the cause of the lock. 您至少可以查看当时锁定文件的人员并从那里开始工作,但如前所述,他们可能不是锁定的原因。 They may have just inherited the lock type. 他们可能刚刚继承了锁类型。

Personally I like to use MS Excel to display MS Access data for users, but avoid like a plague getting it to update MS Access. 就个人而言,我喜欢使用MS Excel为用户显示MS Access数据,但避免像瘟疫一样让它更新MS Access。 However if I was to do this I would do it through the use of oConn.Execute commands not opening a recordset, comparing and slowing pushing as that would keep the connection open too long. 但是,如果我这样做,我会通过使用oConn.Execute命令来打开记录集,比较和减慢推送,因为这会使连接打开太长时间。

Sorry for the wall of text. 抱歉,文字墙。 Hope this information helps. 希望这些信息有所帮助

You could also try using action queries. 您也可以尝试使用操作查询。 First I would try to update using (you may need to format the now value) 首先我会尝试更新使用(您可能需要格式化现在的值)

dim count as long
oConn.Execute "UPDATE need_rows SET quantity = " & Range("B" & r).Value & ", updated_at = #" & Now & "# WHERE service_center = '" & Range("scenter_name").Value & "' AND identifier='" & Range("D" & r).Value & "' AND quantity <> " & Range("B" & r).Value", count

If count is zero then no row was updated, so either there was no row to update or the quantity hasn't changed. 如果count为零,则没有更新行,因此要么没有要更新的行,要么没有更改数量。 Either way we can try to INSERT, which will fail in the latter case, but without causing problems. 无论哪种方式,我们都可以尝试INSERT,在后一种情况下会失败,但不会导致问题。

if count = 0 then
    count = oConn.Execute "INSERT ...", count
    if count = 0 then
        ' quantity has not changed, so nothing to do
    else
        ' new record inserted
    end if
else
    ' record updated
end if

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM