获取最后插入记录的 ID - Access DAO、ODBC、SQL Server 2008 身份字段

Posted

技术标签:

【中文标题】获取最后插入记录的 ID - Access DAO、ODBC、SQL Server 2008 身份字段【英文标题】:Get ID of Last Inserted Record - Access DAO, ODBC, SQL Server 2008 Identity Field 【发布时间】:2012-06-05 21:58:45 【问题描述】:

这是一个非常常见的问题,但我无法获取最后插入的记录的 ID。我正在使用带有 ODBC 链接表的 DAO 来复制一条记录,它是子记录。我的表在 SQL Server 2008 中,并有 ID 字段的标识字段。

这是我迄今为止尝试过的。我这里的第一段代码导致错误 3167,记录已删除。如果我进行调试。打印记录集实际上包含 3 条记录。

Dim r as DAO.Recordset, db as DAO.Database
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 2 * FROM item ORDER BY DateTimeModified DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
'Set field values here
r.Update 'Completes without error
r.Bookmark = r.LastModified
Debug.Print r("ItemID") 'Error 3167, Record is deleted

这是我尝试的下一件事:

Debug.Print db.OpenRecordset("SELECT @@identity FROM item")(0)

最后一个完成没有任何问题,但返回的值不正确。如果实际的新 ItemID 为 321,则返回值 614。它返回的值似乎是增量的(随着我不断测试它会发生变化),但它似乎与我的表完全无关。没有值为 614 的字段。我已仔细检查以确保我正在查找正确的表。

我知道我可以使用 DLookup 或 DMax 之类的东西,但我认为这在多用户环境中不会被视为防弹。

我想我可以使用带有 ADO 的存储过程来解决这个问题。我想知道这是否是我唯一的选择?

编辑1: 我现在正在使用以下代码,它正在做我需要/想要的事情。我怀疑这与使用 DMax 基本相同。

Dim r as DAO.Recordset, db as DAO.Database
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 1 * FROM item ORDER BY ItemID DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
'Set field values here
r.Update
r.Requery
r.MoveFirst
Debug.Print r("ItemID")

【问题讨论】:

您可以使用直通查询或存储过程吗?我很确定您不应该将@@identity 与 SQL Server (wiki.lessthandot.com/index.php/…) 一起使用。 我认为是 SELECT TOP 2 ... Order by DateTimeModified 搞砸了你。此外,Select @@Identity 不打算与 from 子句一起使用,也不太可能按照您的想法行事。此外,如果您不想使用 SP,您可以尝试执行插入并在一批中选择。例如INSERT INTO ... VALUES ... ; SELECT * FROM items where ItemID = Scope_Identity() @ConradFrix 我在 Recordset 'r' 中尝试了不同的 SELECT 语句,但似乎没有任何区别。 我正在使用这些信息来指导我,但我想它可能不准确:social.msdn.microsoft.com/Forums/en-US/accessdev/thread/… 【参考方案1】:

据我所知@@IDENTITY 不适用于基于游标的插入。 DAO 和 ADO 都在幕后使用光标。

在您.Update 记录后,您应该能够通过读取值来取回身份值。

通过使用 Keyset 语义打开的 ADO 记录集,以下内容对我来说很好:

r.Update
Debug.Print r("ItemID")

通过使用动态集语义打开的 DAO 记录集,以下对我来说很好:

r.Update
r.Bookmark = r.LastModified
Debug.Print r("ItemID")

你应该避免.Requery.MoveFirst,你正在引入并发问题。考虑:

Dim r as DAO.Recordset, db as DAO.Database
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 1 * FROM item ORDER BY ItemID DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
''// Set field values here
r.Update
''// At this point another user adds a new record
r.Requery
r.MoveFirst ''// ORDER BY ItemID DESC means that you're going to see the new user's row
Debug.Print r("ItemID")

【讨论】:

我试图找到一个基于 DAO 的解决方案。 @HK1 我已经更新了我的答案,指出您当前的实施存在问题。 不,您的解决方案在 DAO 中不起作用。是的,理论上另一个用户可以在更新和重新查询之间添加新记录是对的。这也是使用 DMax 的问题。 对于 DAO,您发布了与我相同的代码,导致错误 3167。我怀疑您没有使用带有标识字段和 ODBC 链接表的 SQL Server 2008 重新创建整个环境。 @HK1 我没有。标识字段是什么类型,表的主键是什么?当我们这样做时,Access 是否看到主键?即,您在创建主键后添加了链接表。【参考方案2】:

以下按预期工作(使用 Office 2013 和 SQL Server 2014)

Set rsProjects = db.OpenRecordset("JobProjects", dbOpenDynaset, dbSeeChanges Or dbAppendOnly)
rsProjects.AddNew
rsProjects.Name = 'xyz'
rsProjects.Update
rsProjects.Bookmark = rsProjects.LastModified
lNewProjectID = rsProjects!ProjectID.Value

关键点:我没有使用“SELECT TOP 2”或“SELECT TOP 1”等。我使用了“dbSeeChanges 或 dbAppendOnly”。我在 sql profiler 中验证了打开记录集不会对 SQL Server 产生任何查询。

当您发出更新时,access 会生成一个插入语句,然后立即使用 SELECT @@IDENTITY 来获取新记录的 ID。

已编辑:添加缺少的 .AddNew,删除重复的 .Update。

【讨论】:

使用更新两次,不会报错,更新不添加/编辑等。 @ShamYemul 是的,这是我的代码中的一个错误,我错过了 .AddNew 并且有一个额外的 .Update,将修复我的示例代码。【参考方案3】:

它不能与 sql server 后端一起工作(在多用户应用程序中) )。对于访问表它工作 对于 sql 使用存储过程。这样使用

CREATE PROCEDURE dbo.AddAsset

  @Name VARCHAR(500),
  @URL  VARCHAR(2000),
  @new_identity INT = NULL OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

INSERT dbo.Assets(Name, URL) SELECT @Name, @URL;
SET @new_identity = SCOPE_IDENTITY();

END 
GO

然后在前端使用这个sp

【讨论】:

【参考方案4】:

只需在执行Update 语句之前获取关键字段的值。正如下面评论中所指出的,如果您使用的后端与 Microsoft Access 不同,则此过程将不起作用。但是,如果这是您的用例,并且您只是在寻找有关如何获取最后插入记录的 ID 的一般问题的答案,我会在此处留下此回复。

对于您的示例,您可以使用 Microsoft Access 执行此操作:

Dim r as DAO.Recordset, db as DAO.Database
Dim lKey As Long
Set db = CurrentDb
Set r = db.OpenRecordset("SELECT TOP 2 * FROM item ORDER BY DateTimeModified DESC", dbOpenDynaset, dbSeeChanges)
r.AddNew
    'Set field values here
    'Retrieve the key value before executing the Update
    lKey = r!ItemID
r.Update
Debug.Print lKey

【讨论】:

以上不适用于 SQL 服务器 - 但仅适用于 JET/ACE 表。在保存记录之前,SQL 服务器不会生成也不会返回自动编号 PK 值。您必须首先执行更新,然后最好使用书签属性将记录指针移回“lastmodified”,因为更新时添加(并且仅在添加时)会导致记录指针移出您刚刚“更新”的当前记录.更新现有记录不需要 lastmodifed 书签,但用于新记录。

以上是关于获取最后插入记录的 ID - Access DAO、ODBC、SQL Server 2008 身份字段的主要内容,如果未能解决你的问题,请参考以下文章

获取Access中最后插入的记录的ID

Access SQL:从插入语句或从 DAO.QueryDef 获取受影响记录的标识值

从 Access 获取最后一个插入 ID

从 MS Access 数据库中检索最后插入的 ID

Access 2013 - VBA - 记录集插入获取 ID

如何在没有'id'列的MySql中获取最后插入的记录?