MS Access VBA & SQL 服务器 - 记录集更新时 ODBC 调用失败

MS Access VBA & SQL Server - ODBC Call Failed on .Update of Recordset

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

该应用程序存储 HR 信息,并且有一个功能应该根据就业日期和试用期来构建试用计划到期日期。

函数如下:

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

前几个块是检查格式是否正确的 employeeID 和活动状态。

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

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

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

这里是 运行到目前为止的注释和故障排除:

我不知从何而来...


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

定义记录集(在访问和使用 sql 服务器时)。

Dim rst      AS DAO.Reocdset

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

对于任何 linked sql 服务器 table?

table 必须定义主键。如果您在设计模式下打开访问 linked table(忽略只读警告),然后检查两件事:

首先,即使不是 200%,也要 100% 确定您看到了 PK 定义。

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

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

将 sql 服务器列数据类型从 datetime2(新的默认值)更改为 datetime,然后重新 link tables。现在根据 aobve 在设计中再次检查 table - 检查列数据类型。

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

下一期。

访问打开一个table:

Dim  rst   AS DAO.RecordSet

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

访问打开 linked table 到 sql 服务器。

   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 服务器迁移?然后我在一个相对较大的应用程序中找到了 EVEN,使用全局搜索和替换,(在我的粘贴缓冲区中使用 ,dbOpenDynaset,dbSeeChanges?它不应该花费大约 5 分钟的时间。所以去更改所有 VBA reocrdset现在在 linked tables.

上运行的代码

因此,您必须 add/have/include 像这样打开记录集上的两个额外参数:

Set rst = CurrentDb.OpenRecordset(strSQL, dbOpenDynaset, dbSeeChanges)

还有一些你的

在 sql 服务器 table 设计中,所有位字段必须设置默认值(比如 0)为 false。

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

罪魁祸首 is/was 实际上是此数据库中的字段之一(以及上面的后续代码):“LineNo”

“LineNo”是 SQL 服务器中的保留字。

在实施了各种建议之后,这个从....我什至不记得在哪里但是这里有一篇保留字文章在SQL服务器中以供将来参考:

https://docs.microsoft.com/en-us/sql/t-sql/language-elements/reserved-keywords-transact-sql?view=sql-server-ver15

将对此字段的所有引用从“LineNo”更改为“LineNum”解决了所有错误。