MS Access VBA 和 SQL Server - ODBC 调用在记录集更新时失败

问题描述

我有一个 MS Access 应用程序,我正在使用 sql Server Management Studio (SSMS) 将其转换为 sql Server 后端(仍然是 Access FE)。

该应用程序存储人力资源信息,并且有一个功能应该根据雇佣日期和试用期建立试用期到期日。

功能如下:

Private Sub BtnBuildSked_Click()
    Const SUB_NAME As String = "BtnBuildSked_Click"
    On Error GoTo ErrCond
    Dim ThisReport,myresponse,MyStyle As Integer
    Dim MYDB As Database
    Dim Myrst,PdRec As DAO.Recordset
    'Dim Myfrm As Form
    Dim PdStr As String
    Dim s,strsql As String
    Dim t As TTracking
    
    If Me.PaysrID.Value = "ON LEAVE" Then
        MsgBox ("Record is marked ON LEAVE. Cannot proceed.")
        Exit Sub
    End If
        
    'Set Myfrm = Screen.ActiveForm
    Set MYDB = CurrentDb
    s = "SELECT * FROM tblProbationReports"
    Set Myrst = MYDB.OpenRecordset(s,dbOpenDynaset,dbSeeChanges)
    MyStyle = vbOKOnly + vbExclamation
    
    If IsNull(Me.PaysrID) Then
        MsgBox ("Cannot process for empty Employee ID")
        Exit Sub
    End If
    
    If (IsNull(Me.ApptDate)) Then
        myresponse = MsgBox("Appointment Date field is empty ",vbCritical)
        Exit Sub
    End If
    
    '----- Check that Probation Term ID is not blank
    If (Me.ProbationTermId.Value < 1 Or Me.ProbationTermId.Value > 7 Or IsNull(Me.ProbationTermId)) Then
        myresponse = MsgBox("You must select a probationary period to be able to build a schedule",MyStyle)
        Exit Sub
    End If
    
    '----- Warning that any existing records for this employee will be deleted
    myresponse = MsgBox("Warning!! This will delete any current probation schedule records for this Employee and Line No. combination. Do you want to proceed  ?",vbYesNo)
    Debug.Print myresponse
    If myresponse = 7 Then
        Exit Sub
    End If
    
    '------ Delete prevIoUs Probationary records for employee ; Keys = SS# and Line#
    strsql = "DELETE tblProbationReports.* " & _
             "FROM tblProbationReports " & _
             "WHERE tblProbationReports.LineNo= '" & Me.LineNo & "' and tblProbationReports.PaysrID = '" & Me.PaysrID & "' "
            
    DoCmd.SetWarnings False
    DoCmd.Runsql (strsql)
    DoCmd.SetWarnings True
 
    '----- Point to the approp recoird in Probation Data
    PdStr = "SELECT * " & _
            "FROM [tblProbationData] " & _
            "WHERE [ProbationTermID] = " & Me.ProbationTermId.Value
            
    'Set PdRec = MYDB.OpenRecordset("SELECT * FROM [tblProbationData] WHERE [ProbationTermID] = & me.ProbationTermID.Value & ")
    Set PdRec = MYDB.OpenRecordset(PdStr)
    If Not PdRec.EOF Then
        For ThisReport = 1 To PdRec("ProbationReports")
        
        'With Myrst
            Myrst.AddNew
            Myrst.Fields("LineNumber") = Me.LineNo
            Myrst.Fields("SSNO") = Me.SSNo
            Myrst.Fields("PaysrID") = Me.PaysrID
            Myrst.Fields("ReportNo") = ThisReport
            Select Case ThisReport
                Case 1
                    Myrst.Fields("FromDate") = Me.ApptDate
                    Myrst.Fields("ToDate") = Me.ApptDate + (PdRec("Report1weeks") * 7) '-1
                    Myrst.Fields("DueDate") = Me.ApptDate + (PdRec("Report1weeks") * 7) - 1 - 14
                    Myrst.Fields("SentDate") = Me.ApptDate + (PdRec("Report1weeks") * 7) - 1 - 28
                Case 2
                    Myrst.Fields("FromDate") = Me.ApptDate + (PdRec("Report1weeks") * 7)
                    Myrst.Fields("ToDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks")) * 7) '- 1
                    Myrst.Fields("DueDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks")) * 7) - 1 - 14
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks")) * 7) - 1 - 28
                Case 3
                    Myrst.Fields("FromDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks")) * 7)
                    Myrst.Fields("ToDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks")) * 7) '- 1
                    Myrst.Fields("DueDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks")) * 7) - 1 - 14
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks")) * 7) - 1 - 28
                Case 4
                    Myrst.Fields("FromDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks")) * 7)
                    Myrst.Fields("ToDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks")) * 7) '- 1
                    Myrst.Fields("DueDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks")) * 7) - 1 - 14
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks")) * 7) - 1 - 28
                Case 5
                    Myrst.Fields("FromDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks")) * 7)
                    Myrst.Fields("ToDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks")) * 7) '- 1
                    Myrst.Fields("DueDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks")) * 7) - 1 - 14
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks")) * 7) - 1 - 28
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks")) * 7) - 1 - 42
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks")) * 7) - 1 - 56
                Case 6
                    Myrst.Fields("FromDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks")) * 7)
                    Myrst.Fields("ToDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) '- 1
                    Myrst.Fields("DueDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) - 1 - 14
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) - 1 - 28
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) - 1 - 42
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) - 1 - 56
                Case 7
                    Myrst.Fields("FromDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks")) * 7)
                    Myrst.Fields("ToDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) '- 1
                    Myrst.Fields("DueDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) - 1 - 14
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) - 1 - 28
                    Myrst.Fields("SentDate") = Me.ApptDate + ((PdRec("Report1weeks") + PdRec("Report2weeks") + PdRec("Report3weeks") + PdRec("Report4weeks") + PdRec("Report5weeks") + PdRec("Report6weeks")) * 7) - 1 - 56
            End Select
            Myrst.Fields("Received") = False
            Myrst.Update
        
            
        'End With
        Next ThisReport
        
     End If
      
        'set up tracking manually
        t.Comment = "Build New Schedule"
        t.FieldName = "LineNo"
        t.ItemID = Me.LineNo
        t.NewValue = "New Schedule Built"
        t.OldValue = ""
        t.TableName = "tblProbationReports"
        t.TrackingType = TR_TYPE_NEW
        SaveTrans t
        
     Myrst.Close
     PdRec.Close
    
'Myfrm.SetFocus
Me.Recalc
MsgBox ("Probation dates created")



Exit Sub
ErrCond:
    EventLogging AppSession.UserName,MSG_TYPE_ERROR,Err.Number,Err.Description,MOD_NAME & "." & SUB_NAME,AppSession.AppSilent
End Sub

前几个块是检查正确格式的员工 ID 和活动状态。

代码警告任何新计划都将删除以前的值。

然后应用程序应该根据试用期(各种案例陈述)和就业日期建立新的时间表。

但是当代码下降到 .Update 时,它​​会失败并显示“ODBC 调用失败”。

以下是迄今为止的注意事项和故障排除的概要:

  • 与 BE 的连接没有问题。我能够毫无问题地创建、更新和删除员工记录。通过 Access FE 打开时,我可以看到表中的数据。我可以运行报告。

  • “试用报告”表没有主键,我需要添加主键才能在 SSMS 中创建审计触发器(我知道表应该有主键,但我不是原始开发人员)。

  • 我在“Probation Reports”表中创建了“RecordID”主键并将其设为“Identity”,以便自动增加唯一标识符。

  • 在 SSMS 中使 RecordID“Identity”按顺序递增时,Access 在 Recordset.Open of“Probation Reports”上出错......“具有身份的表需要 dbSeeChanges on Recordset”

  • 尝试 Recordset.Open ("name",dbSeeChanges) 仍然出错,“具有标识的表在打开 Recordset 时需要 dbSeeChanges”。 Access 未读取“dbSeeChanges”选项值

  • 我需要添加一个开放的“类型”(虽然可选),以便 Access 读取“dbSeeChanges”的开放“选项”值。

  • 我已经尝试了 Open "Type" docs.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/database-openrecordset-method-dao(甚至那些没有意义的)。这是 .Update 因“ODBC 连接失败”而中断的地方

  • 我尝试添加“dbOpenoptimistic”的 LockEdit 值选项,但仍然收到“ODBC 调用失败”错误...

我不知道该去哪里...


UPDATE - 根据评论中的反馈,我尝试直接向表中添加值并收到以下错误(截图)

HR APP Error

解决方法

定义记录集(在访问中和使用 sql server 时)。

Dim rst      AS DAO.Reocdset

你可以省略 DAO。但你不应该。

对于任何链接的 sql server 表?

该表必须定义一个 PK。如果您在设计模式下打开访问链接表(忽略仅就绪警告),则检查两件事:

首先,如果不是 200% 确定您看到定义的 PK,则为 100%。

第二:在此期间,检查日期时间列的数据类型。如果它们是代替日期时间的文本,您必须立即停止并解决该问题。

如果日期时间列被视为文本,那么您有两种选择:

将 sql server 列数据类型从 datetime2(新的默认值)更改为 datetime,然后重新链接表。现在按照 aobve 再次检查设计中的表 - 检查列数据类型。

您还可以考虑安装较新的 ODBC Native 11 或更高版本的驱动程序 - 它们支持 datetime2 - 内置的传统 ODBC 驱动程序不支持!!! - 它将这些列视为文本。但是,缺点是您必须在每个工作站上安装本机 11(或更高版本的驱动程序 - 现在版本 17)。因此,这取决于您哪个更省事(在每个工作站上安装本机驱动程序,或者将 sql server 列时间翻转回 datetime 而不是使用 datetime2)。

下一期。

访问打开表:

Dim  rst   AS DAO.RecordSet

set rst = currentdb.OpenReocrdSet(" table name or sql goes here")

Access 打开一个链接表到 sql server。

   Dim rst             As DAO.Recordset
   Dim strSQL          As String
   
   strSQL = "SELECT * FROM tblInvoice where InvoiceNum = " & InvoiceNumber
   
   Set rst = CurrentDb.OpenRecordset(strSQL,dbOpenDynaset,dbSeeChanges)

所以,你总是包含 dbOpenDynaset、dbSeeChanges

如果你刚刚做了一个访问sql server的迁移?然后我在一个相对较大的应用程序中找到了 EVEN,使用全局搜索和替换,(在我的粘贴缓冲区中使用,dbSeeChanges?它不应该花更多的时间说大约 5 分钟的时间。所以去更改现在运行的所有 VBA reocrdset 代码在链接表上。

因此,您必须像这样在打开的记录集上添加/拥有/包含两个额外的参数:

Set rst = CurrentDb.OpenRecordset(strSQL,dbSeeChanges)

还有几个是你的

在 sql server 表设计中,所有位字段都必须为 false 设置一个默认值(比如 0)。

如果您收到可怕的“其他人已更新”记录错误?然后您需要向该表添加一个时间戳列(不要将时间戳与日期时间混淆 - 时间戳就是我们所说的行版本列 - 与日期时间为零,并且您永远不会触摸或编辑或更改那个行版本列。