SELECT SCOPE_IDENTITY() 到 return 最后插入的 ID
SELECT SCOPE_IDENTITY() to return the last inserted ID
关于这个问题有几个答案,但我的问题是关于我拥有的特定代码。
我正在尝试获取在 VBA 代码上执行的此查询的最后插入 ID。
Public Function Execute(cQry As excfw_dbQuery) As ADODB.Recordset
If pConn.State = 0 Then
OpenConnection
End If
qry = "INSERT INTO [some really long query, which actually works]; SELECT SCOPE_IDENTITY()"
On Error Resume Next
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open qry, pConn 'also tried with adOpenKeyset, adLockOptimistic
'some error handling code which is not related to the issue
Set rs = rs.NextRecordset() 'also tried without moving onto the next recordset
pInsertedId = rs.Fields(0).Value
Set Execute = rs 'this is just to pass the query result for SELECT queries
End Function
这应该将最后插入的 ID 保存在 pInsertedId 变量中,但每次插入一行时我都会得到 0。奇怪的是,当我将相同的代码复制并粘贴到 SSMS 中时,它起作用了。
我可能只是将一些唯一的数据插入数据库的一些未使用的列并通过它进行查询。
--更新--
我刚刚注意到,当 运行 一个 SELECT 查询时,rs 对象保持打开状态,直到它超出范围。这是手表部分的屏幕截图:
相反,在插入语句中,它会在查询执行后立即关闭:
事实证明,我要插入的 table 附加了多个触发器。因此,包含 SELECT SCOPE_IDENTITY() 的查询;实际上是第四个查询。为了获得正确的范围,我不得不向前移动 4 个查询。我是如何以编程方式实现的,如下所示。不是很干净(而且可能不是最好的方法),但对我来说很管用。
我基本上继续下一个记录集,直到剩下 none,我通过检查错误号 91(对象变量或未设置块变量)检测到它
Public Function Execute(cQry As excfw_dbQuery) As ADODB.Recordset
If pConn.State = 0 Then
OpenConnection
End If
qry = "INSERT INTO [some really long query, which actually works]; SELECT SCOPE_IDENTITY()"
On Error Resume Next
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open cQry.Query, pConn, adOpenKeyset, adLockOptimistic
'some error handling code which is not related to the issue
On Error Resume Next
'begin loop
Do
'go to next recordset
Set rs = rs.NextRecordset()
'if we're getting error n. 91, it means
'recordsets are exhausted, hence we're getting
'out of the loop
If Err.Number = 91 Then
Err.Clear
Exit Do
End If
'if we are not out of recordsets, check the
'result of the query. If it is bigger then zero,
'it means we hit the jackpot.
If rs.Fields(0).Value > 0 Then
pInsertedId = rs.Fields(0).Value
End If
Loop
On Error GoTo 0
End Function
同样,这不是最干净的方法,也不是最正确的方法,但确实成功了。我愿意接受任何改进或建议。
您可以使用 output
子句显式保存 insert
语句的结果,并使用 select
:
return 结果
qry =
"declare @Ids as ( Id Int );" +
"insert into MyTable ( Name ) " + ' Assuming Id is an identity column.
"output Inserted.Id into @Ids " +
"values ( @Name );" +
"select Id from @Ids;"
来自 output
的文档:
INSERTED Is a column prefix that specifies the value added by the
insert or update operation. Columns prefixed with INSERTED reflect the
value after the UPDATE, INSERT, or MERGE statement is completed but
before triggers are executed.
您可以使用 output
子句从行中获取任何数据(注意复数),例如新插入行的标识列值。 Output
可与 insert
、update
、delete
和 merge
一起使用,并提供对 before 和 after 值在 update
的情况下。一个值得放在口袋里的工具。
关于这个问题有几个答案,但我的问题是关于我拥有的特定代码。
我正在尝试获取在 VBA 代码上执行的此查询的最后插入 ID。
Public Function Execute(cQry As excfw_dbQuery) As ADODB.Recordset
If pConn.State = 0 Then
OpenConnection
End If
qry = "INSERT INTO [some really long query, which actually works]; SELECT SCOPE_IDENTITY()"
On Error Resume Next
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open qry, pConn 'also tried with adOpenKeyset, adLockOptimistic
'some error handling code which is not related to the issue
Set rs = rs.NextRecordset() 'also tried without moving onto the next recordset
pInsertedId = rs.Fields(0).Value
Set Execute = rs 'this is just to pass the query result for SELECT queries
End Function
这应该将最后插入的 ID 保存在 pInsertedId 变量中,但每次插入一行时我都会得到 0。奇怪的是,当我将相同的代码复制并粘贴到 SSMS 中时,它起作用了。
我可能只是将一些唯一的数据插入数据库的一些未使用的列并通过它进行查询。
--更新--
我刚刚注意到,当 运行 一个 SELECT 查询时,rs 对象保持打开状态,直到它超出范围。这是手表部分的屏幕截图:
相反,在插入语句中,它会在查询执行后立即关闭:
事实证明,我要插入的 table 附加了多个触发器。因此,包含 SELECT SCOPE_IDENTITY() 的查询;实际上是第四个查询。为了获得正确的范围,我不得不向前移动 4 个查询。我是如何以编程方式实现的,如下所示。不是很干净(而且可能不是最好的方法),但对我来说很管用。
我基本上继续下一个记录集,直到剩下 none,我通过检查错误号 91(对象变量或未设置块变量)检测到它
Public Function Execute(cQry As excfw_dbQuery) As ADODB.Recordset
If pConn.State = 0 Then
OpenConnection
End If
qry = "INSERT INTO [some really long query, which actually works]; SELECT SCOPE_IDENTITY()"
On Error Resume Next
Dim rs As ADODB.Recordset
Set rs = New ADODB.Recordset
rs.Open cQry.Query, pConn, adOpenKeyset, adLockOptimistic
'some error handling code which is not related to the issue
On Error Resume Next
'begin loop
Do
'go to next recordset
Set rs = rs.NextRecordset()
'if we're getting error n. 91, it means
'recordsets are exhausted, hence we're getting
'out of the loop
If Err.Number = 91 Then
Err.Clear
Exit Do
End If
'if we are not out of recordsets, check the
'result of the query. If it is bigger then zero,
'it means we hit the jackpot.
If rs.Fields(0).Value > 0 Then
pInsertedId = rs.Fields(0).Value
End If
Loop
On Error GoTo 0
End Function
同样,这不是最干净的方法,也不是最正确的方法,但确实成功了。我愿意接受任何改进或建议。
您可以使用 output
子句显式保存 insert
语句的结果,并使用 select
:
qry =
"declare @Ids as ( Id Int );" +
"insert into MyTable ( Name ) " + ' Assuming Id is an identity column.
"output Inserted.Id into @Ids " +
"values ( @Name );" +
"select Id from @Ids;"
来自 output
的文档:
INSERTED Is a column prefix that specifies the value added by the insert or update operation. Columns prefixed with INSERTED reflect the value after the UPDATE, INSERT, or MERGE statement is completed but before triggers are executed.
您可以使用 output
子句从行中获取任何数据(注意复数),例如新插入行的标识列值。 Output
可与 insert
、update
、delete
和 merge
一起使用,并提供对 before 和 after 值在 update
的情况下。一个值得放在口袋里的工具。