如何使用Excel VBA获取新插入记录的ID?

Lun*_*tik 8 sql excel ms-access vba jet

这似乎是一个常见的问题,但是大多数解决方案都是指连接多个SQL命令,我相信无法使用ADO/VBA(我很高兴在这方面显示错误).

我当前插入我的新记录,然后运行一个选择查询使用(我希望)足够的字段,以保证只返回新插入的记录.我的数据库很少被一个人一次访问(查询之间发生另一次插入的风险可以忽略不计),并且由于表的结构,识别新记录通常很容易.

我现在正在尝试更新一个没有多少唯一性范围的表,而不是人工主键.这意味着存在新记录可能不是唯一的风险,并且我不愿意添加字段以强制唯一性.

在这种情况下,将记录插入Access表然后从Excel查询新主键的最佳方法是什么?

谢谢你的回复.我试图开始@@IDENTITY工作,但这总是使用下面的代码返回0.

Private Sub getIdentityTest()
    Dim myRecordset As New ADODB.Recordset
    Dim SQL As String, SQL2 As String

    SQL = "INSERT INTO tblTasks (discipline,task,owner,unit,minutes) VALUES (""testDisc3-3"",""testTask"",""testOwner"",""testUnit"",1);"
    SQL2 = "SELECT @@identity AS NewID FROM tblTasks;"

    If databaseConnection Is Nothing Then
        createDBConnection
    End If

    With databaseConnection
        .Open dbConnectionString
        .Execute (SQL)
        .Close
    End With

    myRecordset.Open SQL2, dbConnectionString, adOpenStatic, adLockReadOnly

    Debug.Print myRecordset.Fields("NewID")

    myRecordset.Close

    Set myRecordset = Nothing
End Sub
Run Code Online (Sandbox Code Playgroud)

有什么突出的责任吗?

但是,考虑到Renaud(下图)提供的警告,使用@@IDENTITY任何其他方法的风险几乎与使用其他任何方法一样多,因此我SELECT MAX现在暂时使用.为了将来参考,虽然我有兴趣看看我上面的尝试有什么问题.

Ren*_*uis 13

关于你的问题:

我现在正在尝试更新一个没有多少唯一性范围的表,而不是人工主键.这意味着存在新记录可能不是唯一的风险,并且我不愿意添加字段以强制唯一性.

如果您正在使用您的主键自动增量,那么你有独特性,你可以使用SELECT @@Identity;得到最后自动生成的ID的值(见下面的注意事项).

如果您没有使用自动增量,并且您要从Access插入记录但是想从Excel中检索最后一个:

  • 确保您的主键是可排序的,因此您可以使用以下任一查询获取最后一个:

    SELECT MAX(MyPrimaryField) FROM MyTable;
    SELECT TOP 1 MyPrimaryField FROM MyTable ORDER BY MyPrimaryField DESC;
    
    Run Code Online (Sandbox Code Playgroud)
  • 或者,如果排序你的主要字段不会给你最后一个,你需要添加一个DateTime字段(比如说InsertedDate)并在每次在该表中创建一个新记录时保存当前日期和时间,这样你就可以得到最后一个一个像这样:

    SELECT TOP 1 MyPrimaryField FROM MyTable ORDER BY InsertedDate DESC;
    
    Run Code Online (Sandbox Code Playgroud)

在这两种情况中,我认为您会发现添加AutoIncrement主键更容易处理:

  • 这不会让你付出太多代价

  • 这将保证您的记录的独特性,而无需考虑它

  • 这将使您更容易选择最新的记录,使用@@Identity或通过主键排序或获取Max().

来自Excel

要将数据导入Excel,您有几个选择:

  • 使用查询创建数据链接,因此您可以直接在Cell或范围中使用结果.

  • 来自VBA的查询:

    Sub GetLastPrimaryKey(PrimaryField as string, Table as string) as variant
        Dim con As String
        Dim rs As ADODB.Recordset
        Dim sql As String
        con = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
              "Data Source= ; C:\myDatabase.accdb"
        sql = "SELECT MAX([" & PrimaryField & "]) FROM [" & MyTable & "];"
        Set rs = New ADODB.Recordset
        rs.Open sql, con, adOpenStatic, adLockReadOnly
        GetLastPrimaryKey = rs.Fields(0).Value
        rs.Close
        Set rs = Nothing
    End Sub
    
    Run Code Online (Sandbox Code Playgroud)

请注意 @@Identity

在标准Access数据库(*)中使用时,您必须小心注意事项@@Identity:

  • 它仅适用于AutoIncrement Identity字段.

  • 它仅在您使用ADO并运行时才可用 SELECT @@IDENTITY;

  • 它返回最新使用的计数器,但这适用于所有表.您不能使用它来返回MS Access中特定表的计数器(据我所知,如果您使用指定表FROM mytable,则会被忽略).
    简而言之,返回的值可能与您期望的完全不同.

  • 您必须在搜索之后直接查询,INSERT以尽量减少获得错误答案的风险.
    这意味着,如果您一次插入数据并需要在其他时间(或其他地方)获取最后一个ID,则无法使用.

  • 最后但并非最不重要的是,仅当通过编程代码插入记录时才设置变量.
    这意味着是通过用户界面添加的记录,@@IDENTITY不会被设置.

(*):@@IDENTITY如果您对数据库使用ANSI-92 SQL模式,则要清楚,行为不同,并且以更具预测性的方式.
但问题是ANSI 92与Access支持的ANSI 89风格略有不同,并且当Access用作前端时,旨在提高与SQL Server的兼容性.


Fio*_*ala 7

如果人工密钥是自动编号,则可以使用@@ identity.

请注意,对于这两个示例,事务与其他事件隔离,因此返回的标识是刚刚插入的标识.您可以通过暂停Debug.Print db.RecordsAffected或Debug.Print lngRecs中的代码并手动将记录插入Table1来测试这一点,继续代码并注意返回的标识不是手动插入的记录,而是之前的记录由代码插入.

DAO示例

'Reference: Microsoft DAO 3.6 Object Library '
Dim db As DAO.Database
Dim rs As DAO.Recordset

Set db = CurrentDb

db.Execute ("INSERT INTO table1 (field1, Crdate ) " _
            & "VALUES ( 46, #" & Format(Date, "yyyy/mm/dd") & "#)")
Debug.Print db.RecordsAffected
Set rs = db.OpenRecordset("SELECT @@identity AS NewID FROM table1")
Debug.Print rs.Fields("NewID")
Run Code Online (Sandbox Code Playgroud)

ADO示例

Dim cn As New ADODB.Connection
Dim rs As New ADODB.Recordset

Set cn = CurrentProject.Connection

cn.Execute ("INSERT INTO table1 (field1, Crdate ) " _
            & "VALUES ( 46, #" & Format(Date, "yyyy/mm/dd") & "#)"), lngRecs
Debug.Print lngRecs
rs.Open "SELECT @@identity AS NewID FROM table1", cn
Debug.Print rs.Fields("NewID")
Run Code Online (Sandbox Code Playgroud)