英文:
Retrieving output parameter from passthrough query in MS Access VBA? PT query execs. a stored procedure inserting a new record, I need to get its id
问题
You can retrieve the output parameter value from a stored procedure using a passthrough query in MS Access VBA by modifying your code like this:
Option Compare Database
Option Explicit
Sub ptqTest()
Dim cdb As DAO.Database
Dim qdf As DAO.QueryDef
Dim rs As DAO.Recordset
Dim woid As Long ' Assuming @woid is of type int in your stored procedure
Set cdb = CurrentDb
Set qdf = cdb.CreateQueryDef("")
qdf.Connect = "ODBC;YOUR_CONNECTION_STRING_HERE" ' Replace with your connection string
qdf.SQL = "EXEC [dbo].[sp_two_Insert] @woTitle='YourTitle', @woWriter=1, @woDate='2023-09-06', @woid=0 OUTPUT;"
' Open the passthrough query
Set rs = qdf.OpenRecordset(dbOpenSnapshot)
' Read the output parameter value
woid = rs(0) ' Assuming the output parameter is the first field returned
rs.Close
Set rs = Nothing
Set qdf = Nothing
Set cdb = Nothing
' Now 'woid' contains the newly created record id
End Sub
Make sure to replace "YOUR_CONNECTION_STRING_HERE" with your actual connection string. This code executes your stored procedure with the provided parameters and retrieves the output parameter value into the 'woid' variable.
英文:
Is there any way to run a stored procedure, using a passthrough query, that has input and output parameters? If so, how can I retrieve the output parameter value in MS Access using VBA?
The stored procedure in question inserts a new record and I need to get the newly created record id.
This is my stored procedure:
ALTER PROCEDURE [dbo].[sp_two_Insert]
@woTitle nvarchar(255),
@woWriter int,
@woDate date,
@woid int = 0 OUTPUT
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO dbo.two (woTitle, writtenby, wodate)
VALUES (@woTitle, @woWriter, @woDate);
SELECT @woid = SCOPE_IDENTITY();
END
Thank you all in advance!
I tried these snippets of code:
Attempt #1:
https://stackoverflow.com/a/46086366/9604983
from Gord Thompson
VBA crashes every time at the line: Set rs = ptq.OpenRecordset
, it gets stuck creating new records indefinitely, so I have to exit the program through the task manager.
But, equally to attempt #1, MS Access crashes at the Set rs = rs.NextRecordset
, with the same consequences.
I don't think the solution given by galla_ under "Replies(1)" section, will work for me , since I need the id of the record created by the insert query, and running a second stored procedure, right after the insert, will certainly get the id of the last record created, but not necessarily the id of the record created by the insert stored procedure that run in the first place.
Here is the VBA code that crashes:
Option Compare Database
Option Explicit
Sub ptqTest()
Dim cdb As DAO.Database
Dim rs As DAO.Recordset
Set cdb = CurrentDb
Set rs=cdb.OpenRecordset("qPtMyPassThroughQ") ‘this is where Ms
Access crashes
rs.Close
Set rs = Nothing
Set cdb = Nothing
End Sub
答案1
得分: 2
下面是代码部分的中文翻译:
如果您想要使用或设置输出参数,那么您的代码应该这样编写:
CREATE PROCEDURE [dbo].[AddHotel]
@FirstName nvarchar(50),
@LastName nvarchar(50),
@HotelName nvarchar(50),
@newPK int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
INSERT INTO tblHotelsA (FirstName, LastName, HotelName)
VALUES (@FirstName, @LastName, @HotelName)
SET @newPK = SCOPE_IDENTITY()
END
请注意,输出值不是通过SELECT语句创建的。因此,上述存储过程执行插入操作,然后设置输出参数。
但是,实际上,我并不认为使用输出值有必要,也没有优势,因为使用SELECT语句返回值要容易得多。
因此,我能想到的唯一使用(和返回)输出参数的MS-Access用例是什么呢?
那将是一个“用例”,其中存储过程是由其他人编写的,因此它是一组现有T-SQL代码例程的一部分(其他例程期望并使用输出参数)。换句话说,当是您的选择时,我不会以这种方式编写存储过程。
然而,让我们仍然展示如何获取/使用/享受返回值,因为在软件开发过程中,您可能会遇到上述用例。
所以,假设上面的存储过程。
因此,MS-Access VBA代码可以这样编写:
这个解决方法涉及在两行额外的代码中“包装”存储过程调用(一个T-SQL变量声明和一个SELECT语句,将输出值转换为DAO记录集返回)。
所以,这将适用于上面的情况:
Dim newPK As Long
Dim strSQL As String
Dim sFirstName As String
Dim sLastName As String
Dim sHotelName As String
sFirstName = "Albert"
sLastName = "Kallal"
sHotelName = "My Cool Hotel"
strSQL = "declare @MyPK int;" & _
"exec dbo.AddHotel " & _
"@FirstName = '" & sFirstName & "'," & _
"@LastName = '" & sLastName & "'," & _
"@HotelName = '" & sHotelName & "'," & _
"@newPK = @MyPK OUTPUT;" & _
"SELECT @MyPK AS MyNewPKTest;"
With CurrentDb.QueryDefs("qryPassR")
.ReturnsRecords = True
.SQL = strSQL
newPK = .OpenRecordset()(0)
End With
现在,注意上述的T-SQL返回值的语法是“反向的”。这不是MS-Access的问题,而是T-SQL所需的令人困惑的语法。返回(输出)参数值仍然位于上述表达式的左侧!
正如我所指出的,上述解决方法仅在您无法更改T-SQL例程时才需要。
然而,如果有人以这种方式编写了上述存储过程,可以这样编写:
CREATE PROCEDURE [dbo].[AddHotel]
@FirstName nvarchar(50),
@LastName nvarchar(50),
@HotelName nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO tblHotelsA (FirstName, LastName, HotelName)
VALUES (@FirstName, @LastName, @HotelName)
select SCOPE_IDENTITY()
END
因此,在上述情况下,我们不使用输出参数(也不需要)。而在设置返回(输出)值的地方呢?
我们使用一个简单的SELECT语句,这将导致返回一个标准的DAO数据行。
所以,我们的VBA代码现在看起来像这样:
strSQL = "exec dbo.AddHotel " & _
"@FirstName = '" & sFirstName & "'," & _
"@LastName = '" & sLastName & "'," & _
"@HotelName = '" & sHotelName & "'"
With CurrentDb.QueryDefs("qryPassR")
.ReturnsRecords = True
.SQL = strSQL
newPK = .OpenRecordset()(0)
End With
或者,它甚至可以以这种格式编写,但需要小心,因为参数的顺序很重要。
因此,这个语法:
strSQL = "exec dbo.AddHotel '" & _
sFirstName & "'," & _
"'" & sLastName & "'," & _
"'" & sHotelName & "'"
With CurrentDb.QueryDefs("qryPassR")
.ReturnsRecords = True
.SQL = strSQL
newPK = .OpenRecordset()(0)
End With
请注意我在返回记录集时使用的简化方法。
这行代码:
newPK = .OpenRecordset()(0)
也可以以长格式编写如下:
Dim rstReturn as DAO.RecordSet
... 同样的上述代码,然后
set rstReturn = .OpenRecordSet
End With
然后要获取值,您可以使用:
rstReturn(0) ' 第一列。
或者,您可以使用T-SQL语句中返回的列名。
rstReturn!newPK, or rstReturn("newPK")
并且如果您要使用列名作为返回值,请确保在T-SQL中设置了该列。
例如:
select SCOPE_IDENTITY() as newPK
因此,VBA DAO不直接支持T-SQL返回(输出)参数。
然而,这种情况很少出现,并且上面的第一个解决方法仅在无法更改T-SQL例程时才需要。
还要注意,我使用了现有创建的传递查询,因此假定连接设置已经创建并设置为那个Access传递查询。
英文:
Ok, you have some errors here.
If you want to use or set an output parameter, then your code should be written like this:
CREATE PROCEDURE [dbo].[AddHotel]
@FirstName nvarchar(50),
@LastName nvarchar(50),
@HotelName nvarchar(50),
@newPK int OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
INSERT INTO tblHotelsA (FirstName, LastName, HotelName)
VALUES (@FirstName, @LastName, @HotelName)
SET @newPK = SCOPE_IDENTITY()
END
Note how the output value IS NOT created by a select. So, the above stored procedure does an insert and THEN sets the OUTPUT parameters.
However, really, I don't see the need, nor advantage of using output values, since it is far easier to return values using SELECT.
So, the only use case I can think of for using (and returning) OUTPUT parameters to MS-access?
That would be a "use case" in which the stored procedure was written by someone else and thus is part of some set of existing T-SQL code routines (and those other routines expect and use OUTPUT parameters). In other words, I would not write the stored procedure that way when it is YOUR choice.
However, let's still show how you can get/use/enjoy that return value, since you may well in your software travels encounter the above use case.
So, say the above stored procedure.
So, the MS-Access VBA code can be written this way:
The work around involves "wrapping" the stored procedure call in 2 extra lines of code. (a T-SQL variable declare, and a SELECT statement to turn that output value into a DAO recordset return).
So, this will work for above:
Dim newPK As Long
Dim strSQL As String
Dim sFirstName As String
Dim sLastName As String
Dim sHotelName As String
sFirstName = "Albert"
sLastName = "Kallal"
sHotelName = "My Cool Hotel"
strSQL = "declare @MyPK int;" & _
"exec dbo.AddHotel " & _
"@FirstName = '" & sFirstName & "'," & _
"@LastName = '" & sLastName & "'," & _
"@HotelName = '" & sHotelName & "'," & _
"@newPK = @MyPK OUTPUT;" & _
"SELECT @MyPK AS MyNewPKTest;"
With CurrentDb.QueryDefs("qryPassR")
.ReturnsRecords = True
.SQL = strSQL
newPK = .OpenRecordset()(0)
End With
Now, NOTE BEYOND CLOSE in above:
Note how the T-SQL syntax for a return value is "backwards". This is not a MS-Access face plant, but is the confusing syntax required for T-SQL. The parameter value returned remains on the LEFT SIDE of the above expression!
As I noted, the above is a workaround ONLY required if you are stuck with an existing stored procedure that you can't change.
However, one would write the above stored procedure this way:
CREATE PROCEDURE [dbo].[AddHotel]
@FirstName nvarchar(50),
@LastName nvarchar(50),
@HotelName nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO tblHotelsA (FirstName, LastName, HotelName)
VALUES (@FirstName, @LastName, @HotelName)
select SCOPE_IDENTITY()
END
So, in above, we don't use an output parameter (and don't need one). And in place of a SET command to set the return (output) value?
We use a simple SELECT statement, and that results in a single standard DAO data row being returned.
So, our VBA code now looks like this:
strSQL = "exec dbo.AddHotel " & _
"@FirstName = '" & sFirstName & "'," & _
"@LastName = '" & sLastName & "'," & _
"@HotelName = '" & sHotelName & "'"
With CurrentDb.QueryDefs("qryPassR")
.ReturnsRecords = True
.SQL = strSQL
newPK = .OpenRecordset()(0)
End With
Or, it could even be written in this format, but then caution is required since parameter order matters.
So, this syntax:
strSQL = "exec dbo.AddHotel '" & _
sFirstName & "','" & sLastName & "','" & sHotelName & "'"
With CurrentDb.QueryDefs("qryPassR")
.ReturnsRecords = True
.SQL = strSQL
newPK = .OpenRecordset()(0)
End With
And note the short hand I am using for the return recordset.
This line of code:
newPK = .OpenRecordset()(0)
could be written in long format as this:
dim rstReturn as DAO.RecordSet
... same above code here, and then
set rstReturn = .OpenRecordSet
End With
Then to get the value, you use:
rstReturn(0) ' first column.
Or, you could use the returned column name from the T-SQL statement.
rstReturn!newPK, or rstReturn("newPK")
And again if you going to use a column name for the return value, then make sure you set that column in the T-SQL
eg this:
select SCOPE_IDENTITY() as newPK
So, VBA DAO does not directly support T-SQL return (output) parameters.
However, it is rare they are warranted, and the above first work around only is required when you can't change the T-SQL routines.
Note also how I use an exiting created pass-though query, and thus the connection setup is assumed to have already been created and setup for that Access pass-though query.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论