MS SQL 2008/Access 2002 VBA - 检查数据库的当前记录,如果不存在则输入

Posted

技术标签:

【中文标题】MS SQL 2008/Access 2002 VBA - 检查数据库的当前记录,如果不存在则输入【英文标题】:MS SQL 2008/Access 2002 VBA - Check DB for current record, if does not exist then enter it 【发布时间】:2015-07-23 16:12:12 【问题描述】:

我正在尝试创建一个 SQL 字符串,该字符串将检查表 Notification 的当前记录条件(两个不同的 ID 值)。如果它找到具有这两个值的记录,它将不会将该记录输入到表中。如果它没有找到它,它会。

我已经尝试使用 VBA 来解决这个问题,但似乎我能够做到这一点的唯一方法是使用 SQL,因为 Access 字段类型与SQL 字段类型(IE:整数在 SQL 中可以,但在 Access VBA 中导致溢出的值)。

我一直在尝试找到某种 WHERE 语句,它可以让我检查表以查看 AssetID 和 NotificationTypeID 是否已经在表中。如果是,则忽略插入并继续。

我已经看到其他类型的 SQL 示例可以回答这个问题,但我无法让它们在 VBA 中工作。

更新的代码(注意:'我知道,AssetID 应该是长的。它是 SQL 中的一个 Int,但是当在 vba 中为 Access 设置为 Int 时,我收到一条溢出消息 '当我尝试将其设置为 long 时,会出现类型不匹配。字符串目前似乎可以在 SQL 中用于将值放入数据库)

这仍然无法在 .AddNew 中使用。它应该,但由于某种原因会返回一个 Invalid Operation 错误。

Dim Response As Integer
Dim strSQL As String
Dim delSQL As String
Dim NotTypeID As String
Dim NotDate As Date
Dim AssetId As String
Dim rcdCount As Integer
Dim i As Integer 
Dim rst As DAO.Recordset
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rcd As DAO.Recordset
Dim strSelect As String

strGroup = ReturnGroup

'Check user credentials before showing notifications

If InStr(1, strGroup, "Not_admins") Or InStr(1, strGroup, "Admins") Then


        DoCmd.SetWarnings True

    'Check the Storage Location query, see if there is a reason to notify the user
    If DCount("*", "qry_UnknownStorageLoc") > 0 Then

        'Getting the record count from the query
        rcdCount = DCount("*", "qry_UnknownStorageLoc")

        'This is the popup message box that is shown to the user when Fassetrack loads
        'Response = MsgBox("Notice: " & DCount("*", "qry_UnknownStorageLoc") & " record(s) which contain an unknown storage location", vbInformation + vbOKOnly, "UnknownStorage")

        strSQL = "SELECT AssetID FROM qry_UnknownStorageLoc"

        Set db = CurrentDb
        Set rst = db.OpenRecordset(strSQL, dbOpenSnapshot)
        i = 1

        'Loop through to gather all the records for this notification type
        'and add them to the Notifications table

        With rst
            Do Until .EOF

                'Set the AssetID value, then move to the next record in the query
                AssetId = rst!AssetId

                'NotTypeID is the id of the notification type in the NotificationType table
                NotTypeID = 1

                rst.MoveNext

                'Setting the notification date to the last date the record was modified with
                'the logic being the last edit triggered the notification. When the record is
                'corrected and/or acknowledged, it will no longer trigger a notification.

                'Null checking to ensure no errors occur

                If (IsNull(DLookup("modifiedon", "qry_UnknownStorageLoc"))) Then
                    NotDate = 0
                Else
                    NotDate = DLookup("modifiedon", "qry_UnknownStorageLoc")
                End If

                '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
                strSelect = "SELECT n.NotificationTypeID, n.NotificationDate, n.AssetID" & vbCrLf & _
                    "FROM Notifications AS n" & vbCrLf & _
                    "WHERE n.NotificationTypeID = [pType] AND n.NotificationDate = [pDate] AND n.AssetID = [pID];"
                Debug.Print strSelect

                Set qdf = db.CreateQueryDef(vbNullString, strSelect)
                With qdf
                    .Parameters("pType").Value = NotTypeID
                    .Parameters("pDate").Value = NotDate
                    .Parameters("pID").Value = AssetId
                    Set rs = .OpenRecordset(dbOpenDynaset, dbSeeChanges)
                End With

                With rs
                    If .BOF And .EOF Then
                        .AddNew
                        !NotificationTypeID.Value = NotTypeID
                        !NotificationDate.Value = NotDate
                        !AssetId.Value = AssetId
                        .Update
                    End If
                    .Close

                End With
                i = i + 1

            Loop
        End With

        'Close and clear the recordset
        rst.Close
        Set rst = Nothing
    End If

【问题讨论】:

阻止我使用 VBA 解决此问题的一个问题是,有问题的 ID 是 SQL 数据库中的整数。当它通过 Access 时会出现问题,因为值超过 32000+,所以出现了溢出错误。我无法更改这些类型,因为它们是预先存在并自动递增的。 查看之前的帖子***.com/questions/19573198/…。看起来您必须先检查是否存在,然后才能运行插入语句。 【参考方案1】:

考虑基于参数查询从临时QueryDef 加载记录集。如果记录集为空,则不存在匹配记录,可以添加记录。

Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim strSelect As String

strSelect = "SELECT n.NotificationTypeID, n.NotificationDate, n.AssetID" & vbCrLf & _
    "FROM Notification AS n" & vbCrLf & _
    "WHERE n.NotificationTypeID = [pType] AND n.NotificationDate = [pDate] AND n.AssetID = [pID];"
'Debug.Print strSelect
Set db = CurrentDb
Set qdf = db.CreateQueryDef(vbNullString, strSelect)
With qdf
    .Parameters("pType").Value = NotTypeID
    .Parameters("pDate").Value = NotDate
    .Parameters("pID").Value = AssetId
    'Set rs = .OpenRecordset
    Set rs = .OpenRecordset(dbOpenDynaset, dbSeeChanges)
End With
With rs
    If .BOF And .EOF Then
        .AddNew
        !NotificationTypeID.Value = NotTypeID
        !NotificationDate.Value = NotDate
        !AssetID.Value = AssetId
        .Update
    End If
    .Close
End With

【讨论】:

在我们发言时正在处理这个问题。与此相关的一个问题:您能否将多个 DAO 记录集打开到同一个数据库但不同的表? 是的,这是可能的。不过,我不明白这如何适用于这个问题。 我的表名有误:Notifications 而不是 Notification。由于这是指向 SQL Server 表的链接,请尝试使用我添加到 OpenRecordset 的选项 dbOpenSnapshot 会给你一个只读的记录集,所以你不想要那个。如果您在导航窗格中找到该 Notification 表,并从那里在数据表视图中打开,您可以手动添加记录吗? 我怀疑.OpenRecordset(dbOpenDynaset, dbSeeChanges) 是问题所在。我用我自己的链接 SQL Server 表测试了该代码,它按预期工作。我不明白为什么它不适合你,但我不能在这上面投入更多时间。我可以删除这个答案,你可以将你的问题恢复到原来的状态,然后也许其他人可以想出如何帮助你。【参考方案2】:

首先非常感谢cars10和HansUp,你们让我朝着正确的方向前进。

我决定退出 QueryDef 只是因为我对它们还不够熟悉。这是工作结果。

Dim db As DAO.Database
Dim rst As DAO.Recordset
Dim rs As DAO.Recordset

Dim response As Integer
Dim strSQL As String
Dim strSelect As String
Dim notTypeID As Integer
Dim notItemcode As String
Dim notDate As Date
Dim notAssetId As Long
Dim rcdCount As Integer
Dim i As Integer

'Check the Storage Location query, see if there is a reason to notify the user
    If DCount("*", "qry_UnknownStorageLoc") > 0 Then

        'Set warnings to true to catch any potential errors
        DoCmd.SetWarnings True

        'Getting the record count from the query
        rcdCount = DCount("*", "Notifications", "NotificationTypeID = 1")

        'Set db to the current database and rst to the current recordset from the query qry_OilSolvActNotification
        strSQL = "SELECT AssetID, BarcodeNumber  FROM qry_UnknownStorageLoc WHERE (AssetID NOT IN (SELECT AssetID From Notifications Where NotificationTypeID = 1))"
        Set db = CurrentDb
        Set rst = db.OpenRecordset(strSQL, dbOpenSnapshot)

        Debug.Print rst.RecordCount

        i = 1

        'Loop through to gather all the records for this notification type
        'and add them to the Notifications table

        With rst
            Do Until rst.EOF

                'Set the AssetID value, then move to the next record in the query
                notAssetId = rst!AssetId
                notItemcode = rst!BarcodeNumber

                'NotTypeID is the id of the notification type in the NotificationType table
                notTypeID = 1

                rst.MoveNext

                'Setting the notification date to the last date the record was modified with
                'the logic being the last edit triggered the notification. When the record is
                'corrected and/or acknowledged, it will no longer trigger a notification.

                'Null checking to ensure no errors occur

                If (IsNull(DLookup("modifiedon", "qry_UnknownStorageLoc"))) Then
                    notDate = 0
                Else
                    notDate = DLookup("modifiedon", "qry_UnknownStorageLoc")
                End If

                strSelect = "Select * from Notifications WHERE CLng(AssetID) = '" & notAssetId & "' AND ItemCode = '" & notItemcode & "' AND CInt(NotificationTypeID) = '" & CInt(notTypeID) & "'"

                'Set the rs recordset with the records from the table Notifications that match the SQL statement criteria
                Set rs = db.OpenRecordset(strSelect, dbOpenDynaset, dbSeeChanges)

                'Loop the rs recordset. If there is a record to be entered into the Notifications table, insert it.
                With rs
                    If rs.BOF And rs.EOF Then

                        'Set Warnings to false so the user is not presented with a confirmation to add a record every time there is one available.
                        DoCmd.SetWarnings False

                        strSelect = "INSERT INTO Notifications (NotificationTypeID, NotificationDate, AssetID, ItemCode) VALUES('" & notTypeID & "','" & notDate & "','" & notAssetId & "', '" & notItemcode & "');"

                        DoCmd.RunSQL strSelect

                    End If

                    'Close the recordset
                    rs.Close

                End With

                'Clear the recordset
                Set rs = Nothing

                i = i + 1

            Loop
        End With

        'Close and clear the recordset
        rst.Close
        Set rst = Nothing
    End If

    'This is the popup message box that is shown to the user when Fassetrack loads
    response = MsgBox("Notice: " & DCount("*", "Notifications", "NotificationTypeID = 1") & " record(s) which contain an unknown storage location", vbInformation + vbOKOnly, "Fassetrack")

【讨论】:

以上是关于MS SQL 2008/Access 2002 VBA - 检查数据库的当前记录,如果不存在则输入的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SQL for MS Access 中实现分页?

如何在 SQL for MS Access 中实现分页?

将 PDO 与 MS SQL 结合使用“活动结果不包含任何字段”

有没有办法在 VBA(MS Access 2002 或 2003)中调用任何控件的更新前事件过程?

MS SQL为字段添加说明

MS SQL为字段添加说明