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的兼容性.
如果人工密钥是自动编号,则可以使用@@ 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)