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 可与 insertupdatedeletemerge 一起使用,并提供对 beforeafter 值在 update 的情况下。一个值得放在口袋里的工具。