I have a stored procedure that calls another stored procedure. The inner stored procedure returns a result set. After using a CallableStatement
to execute the calling stored procedure I am unable to get the result set returned by called stored procedure.
I tried both execute
and executeQuery
for execution of callable statement. When I execute the calling stored procedure from SQL Server I am getting proper results.
Calling procedure:-
ALTER PROC [User].[Get_Data]
(@UserID NVARCHAR(20))
AS
BEGIN
Select 'User Data'
Exec [Order].[Get_Order] @UserID
END
Called procedure:-
ALTER PROC [Order].[Get_Order]
(@UserID NVARCHAR(20))
AS
BEGIN
Select * from orders where userId=@UserID
END
Your outer stored procedure is returning two result sets:
Select 'User Data'
Exec [Order].[Get_Order] @UserID
You need to call .getMoreResults()
in order to retrieve the second result set, eg,
CallableStatement cs = connection.prepareCall("{CALL Get_Data (?)}");
cs.setString(1, "gord");
ResultSet rs = cs.executeQuery();
System.out.println("[First result set]");
while (rs.next()) {
System.out.printf("(No column name): %s%n", rs.getString(1));
}
cs.getMoreResults();
rs = cs.getResultSet();
System.out.println();
System.out.println("[Second result set]");
while (rs.next()) {
System.out.printf("userId: %s, orderId: %s%n",
rs.getString("userId"), rs.getString("orderId"));
}
producing
[First result set]
(No column name): User Data
[Second result set]
userId: gord, orderId: order1
userId: gord, orderId: order2
(Tested using mssql-jdbc-6.2.1.jre8.jar connecting to SQL Server 2014.)
For more details, see
How to get *everything* back from a stored procedure using JDBC
You cannot select the results of a stored procedure directly within SQL Server itself. You need to first insert the result into a temp table as per example below.
Example use:
-- Create a tempoary table to store the results.
CREATE TABLE #UserOrderDetail
(
UserData NVARCHAR(50) -- Your columns here
)
-- Insert result into temp table.
-- Note that the columns returned from procedure has to match columns in your temp table.
INSERT INTO #UserOrderDetail
EXEC [Order].[Get_Order] @UserID
-- Select the results out of the temp table.
SELECT *
FROM #UserOrderDetail
If the intent is to simply return one or more result sets to a client application, you should ensure that the SET NOCOUNT ON statement is added to the top of your stored procedures, this will prevent SQL Server from sending the DONE_IN_PROC messages to the client for each statement in the stored procedure. Database libraries like ODBC, JDBC and OLEDB can get confused by the row counts returned by the various insert and update statements executed within a SQL Server stored procedures. Your original procedure will look as follow:
ALTER PROC [User].[Get_Data]
(
@UserID NVARCHAR(20)
)
AS
BEGIN
SET NOCOUNT ON
SELECT 'User Data'
EXEC [Order].[Get_Order] @UserID
END
Getting this right with JDBC is quite hard. The accepted answer by Gord Thompson might work, but it doesn't follow the JDBC spec to the word, so there might be edge cases where it fails, eg when there are interleaved update counts (known or accidental), or exceptions / messages.
I've blogged about the correct approach in detail here . The Oracle version is even more tricky, in case you need it . So here it goes:
// If you're daring, use an infinite loop. But you never know...
fetchLoop:
for (int i = 0, updateCount = 0; i < 256; i++) {
// Use execute(), instead of executeQuery() to handle
// leading update counts or exceptions
boolean result = (i == 0)
? s.execute()
: s.getMoreResults();
// Warnings here
SQLWarning w = s.getWarnings();
for (int j = 0; j < 255 && w != null; j++) {
System.out.println("Warning : " + w.getMessage());
w = w.getNextWarning();
}
// Don't forget this
s.clearWarnings();
if (result)
try (ResultSet rs = s.getResultSet()) {
System.out.println("Result :");
while (rs.next())
System.out.println(" " + rs.getString(1));
}
else if ((updateCount = s.getUpdateCount()) != -1)
System.out.println("Update Count: " + updateCount);
else
break fetchLoop;
}
Note that in case you're using jOOQ, you could leverage code generation for your stored procedures and call the simplified API to do this in a few lines only:
GetDatap = new GetData();
p.setUserId("gord");
p.execute(configuration);
Results results = p.getResults();
for (Result<?> result : results)
for (Record record : result)
System.out.println(record);
Disclaimer: I work for the company behind jOOQ
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.