获取最后插入记录的 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 SQL:从插入语句或从 DAO.QueryDef 获取受影响记录的标识值