简体   繁体   English

通过 ODBC SQL 链接表在 Access 中打开 2 个记录集

[英]Opening 2 recordsets in Access via ODBC SQL Linked Table

I am working on converting our multiple access (2016) files / databases into one consolidated access file with navigation, and the data hosted on a SQL server (2014).我正在努力将我们的多访问 (2016) 文件/数据库转换为一个带有导航的统一访问文件,并将数据托管在 SQL 服务器 (2014) 上。 Currently, we have a button that has the below code, and every time I get to an s.update line, I get the error "new transaction is not allowed because there are other threads running in the session".目前,我们有一个包含以下代码的按钮,每次我到达 s.update 行时,都会收到错误消息“不允许新事务,因为会话中有其他线程正在运行”。

I've been Googling for a day or 2 now and can't seem to get rid of it.我已经在谷歌上搜索了一两天,似乎无法摆脱它。 I read that enabling MARS could help since I have 2 recordsets open, but that did not help.我读到启用 MARS 会有所帮助,因为我打开了 2 个记录集,但这没有帮助。 I do see the "MARS_Connection=Yes" on that tables connection string.我确实在该表连接字符串上看到了“MARS_Connection=Yes”。 I've also read that for loops can cause issues but none of the s.update lines are actually in a for loop.我还读到 for 循环可能会导致问题,但实际上没有 s.update 行在 for 循环中。 I've had trouble finding this issue in relation to Access我很难找到与 Access 相关的这个问题

I'm relearning VBA as I go, I did not write this app and am open for suggestions.我正在重新学习 VBA,我没有编写这个应用程序,我愿意接受建议。

Private Sub cmdNewWeek_Click()
    On Error GoTo ErrorHandler
    Dim r As DAO.Recordset, s As DAO.Recordset, f As Field, DifferentDate As Boolean, d As Date
    d = Date - (Weekday(Date) - 2)

    If IsNull(Me.cboSelAtty) Then
        MsgBox "Select an attorney first."
        cboSelAtty.SetFocus
    Else
        If IsNull(Me.employee) Then Me.employee = Me.cboSelAtty
        DoCmd.RunCommand acCmdSaveRecord
        DifferentDate = False
        MsgBox cboSelAtty
        Set r = CurrentDb.OpenRecordset("Select top 1 * From kt_workload Where employee=" & CSql(cboSelAtty) & " Order By week Desc", dbOpenSnapshot)
        Set s = CurrentDb.OpenRecordset("kt_workload", dbOpenDynaset, dbSeeChanges)
        If r.EOF Then
            s.AddNew
            s("employee") = cboSelAtty
            s("week") = d
            s.Update
            s.Close
            r.Close
            Me.Requery
            Exit Sub
        ElseIf r("week") >= d Then
            If MsgBox("A record for this week already exists. Do you want to enter one for a different week?", vbCritical + vbYesNo) = vbNo Then
                r.Close
                Exit Sub
            Else
                DifferentDate = True
            End If
        End If
        s.AddNew
        For Each f In r.Fields
            If f.Name <> "week" Then s(f.Name) = r(f.Name)
        Next
        s("week") = IIf(DifferentDate, r("week") + 7, d)
        s.Update
        s.Close
        r.Close
        Me.Requery
    End If
ErrorHandler:
    'Start ODBC error Catch
    Dim i As Integer
    Dim st As String
    For i = 0 To Errors.Count - 1
        st = st & Errors(i).Description & vbCrLf
    Next i
    MsgBox st, vbCritical
    'End ODBC error Catch
End Sub

Example Data (I couldn't get the table to format properly for whatever reason): Example Data示例数据(无论出于何种原因,我都无法正确格式化表格):示例数据

In the end, all we are doing is copying the most recent record as the 'test' fields are often similar week to week.最后,我们所做的只是复制最近的记录,因为“测试”字段通常每周都相似。

Edit: I trimmed down the function to the below.编辑:我将功能缩减到以下。 I do get 1 record back from my "r" record as expected.我确实按预期从“r”记录中获得了 1 条记录。 It gets applied to the "s" new record just fine.它可以很好地应用于“s”新记录。

but s.update throws the same error.但 s.update 抛出同样的错误。 Also, if I run this and run a SQL query through SSMS, that query hangs up until the access form throws the error (~60 seconds), so I'm not sure where I am going wrong with the SQL connection side I assume.此外,如果我运行它并通过 SSMS 运行 SQL 查询,该查询将挂起,直到访问表单抛出错误(约 60 秒),所以我不确定我假设的 SQL 连接端哪里出了问题。

Trimmed Down Code:精简代码:

Private Sub cmdNewWeek_Click()
    On Error GoTo ErrorHandler
    Dim r As DAO.Recordset, s As DAO.Recordset, DifferentDate As Boolean, d As Date
    d = Date - (Weekday(Date) - 2)
    Set r = CurrentDb.OpenRecordset("Select top 1 * From kt_workload Where employee=" & CSql("jcraig") & " Order By week Desc", dbOpenSnapshot)
    Set s = CurrentDb.OpenRecordset("kt_workload", dbOpenDynaset, dbSeeChanges)
    s.AddNew
    For Each f In r.Fields
        If f.Name <> "week" Then s(f.Name) = r(f.Name)
        Debug.Print s(f.Name)
    Next
    s("week") = d
    s.Update
    s.Close
    r.Close
        
ErrorHandler:
    'Start ODBC error Catch
    Dim i As Integer
    Dim st As String
    For i = 0 To Errors.Count - 1
        st = st & Errors(i).Description & vbCrLf
    Next i
    MsgBox st, vbCritical
    'End ODBC error Catch
End Sub

Whenever you need a recordset to only read data from, you should open it as snapshot .每当您需要一个仅从中读取数据的记录集时,您应该将其作为快照打开。

In your case you only want to read the first record, so you should also use TOP 1 .在您的情况下,您只想读取第一条记录,因此您还应该使用TOP 1

Should you ever have an attorney named O'Brien , your code will break.如果您有一位名叫O'Brien的律师,您的密码就会失效。 Use Gustav's CSql() function when concatenating variables with SQL.将变量与 SQL 连接时,请使用 Gustav 的CSql()函数 It handles all strings and prevents SQL injection.它处理所有字符串并防止 SQL 注入。

In summary:总之:

strSql = "Select TOP 1 * From table1 Where employee=" & CSql(cboSelAtty) & " Order By week Desc"
Set r = CurrentDb.OpenRecordset(strSql, dbOpenSnapshot)

This way you won't have conflicting transactions.这样你就不会有冲突的交易。

Note that your ODBC error handling loop should go into an On Error Goto xxx handler.请注意,您的 ODBC 错误处理循环应该进入On Error Goto xxx处理程序。

In the end, I think this is some connection issue unique probably to access 2016, SQL Server 2014 and ODBC 17 drivers.最后,我认为这是访问 2016、SQL Server 2014 和 ODBC 17 驱动程序所特有的一些连接问题。 Instead of doing the double recordsource, I'm opening up the read recordsource and just using the values to insert a new record, and then I'll just select this new record.我没有使用双记录源,而是打开读取记录源并仅使用这些值插入新记录,然后我将只选择这条新记录。 It works now at least.它至少现在有效。

  sql = "INSERT INTO kt_workload (employee, week, availweek, availMonth, availQtr, activeWeek, activeMonth, activeQtr) VALUES (" & _
          CSql(r("employee")) & ",'" & _
          r("week") & "'," & _
          CSql(r("availweek")) & "," & _
          CSql(r("availMonth")) & "," & _
          CSql(r("availQtr")) & "," & _
          CSql(r("activeWeek")) & "," & _
          CSql(r("activeMonth")) & "," & _
          CSql(r("activeQtr")) & _
          ");"
Debug.Print sql
CurrentDb.Execute sql

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

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