我的老板给了我一个存储过程,该存储过程应该返回一个代码,该代码指示它是成功还是存在问题。为了访问此过程并获取返回代码,我使用以下代码:
SQLServerDataSource src = makeConnection();
CallableStatement statement = null;
ResultSet resultSet = null;
try(Connection conn = src.getConnection())
{
statement = conn.prepareCall("{ ? = call uspGetBillOfMaterials(?,?) }");
statement.registerOutParameter(1,Types.INTEGER);
statement.setInt("StartProductID",733);
statement.setString("CheckDate","2018-02-18 00:00:00.000");
resultSet = statement.executeQuery();
if(resultSet != null)
{
System.out.println("Query was successful. Code: "+resultSet.getInt(1));
}
}
catch (Throwable t)
{
t.printStackTrace();
}
应该注意,我在Microsoft SQL Server中使用JDBC。我正在使用用于SQL Server的Microsoft JDBC驱动程序。
不幸的是,当我执行此代码时,出现以下异常:
com.microsoft.sqlserver.jdbc.SQLServerException: The result set has no current row.
at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDriverError(SQLServerException.java:226)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.verifyResultSetHasCurrentRow(SQLServerResultSet.java:534)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.getterGetColumn(SQLServerResultSet.java:2006)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.getValue(SQLServerResultSet.java:2037)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.getValue(SQLServerResultSet.java:2023)
at com.microsoft.sqlserver.jdbc.SQLServerResultSet.getInt(SQLServerResultSet.java:2297)
...
--- The rest removed for brevity---
我相信我的代码对于获取返回值是正确的。我想念什么吗?
还是存储过程编写不正确?存储过程如下:
USE [AdventureWorks2014]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[uspGetBillOfMaterials] @StartProductID [int]
,@CheckDate [datetime]
AS
BEGIN
DECLARE @ReturnCode INT = 0
,@logrowcount VARCHAR(36)
SET NOCOUNT ON;
-- Use recursive query to generate a multi-level Bill of Material (i.e. all level 1
-- components of a level 0 assembly, all level 2 components of a level 1 assembly)
-- The CheckDate eliminates any components that are no longer used in the product on this date.
WITH [BOM_cte] (
[ProductAssemblyID]
,[ComponentID]
,[ComponentDesc]
,[PerAssemblyQty]
,[StandardCost]
,[ListPrice]
,[BOMLevel]
,[RecursionLevel]
) -- CTE name and columns
AS (
SELECT b.[ProductAssemblyID]
,b.[ComponentID]
,p.[Name]
,b.[PerAssemblyQty]
,p.[StandardCost]
,p.[ListPrice]
,b.[BOMLevel]
,0 -- Get the initial list of components for the bike assembly
FROM [Production].[BillOfMaterials] b
INNER JOIN [Production].[Product] p ON b.[ComponentID] = p.[ProductID]
WHERE b.[ProductAssemblyID] = @StartProductID
AND @CheckDate >= b.[StartDate]
AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate)
UNION ALL
SELECT b.[ProductAssemblyID]
,b.[ComponentID]
,p.[Name]
,b.[PerAssemblyQty]
,p.[StandardCost]
,p.[ListPrice]
,b.[BOMLevel]
,[RecursionLevel] + 1 -- Join recursive member to anchor
FROM [BOM_cte] cte
INNER JOIN [Production].[BillOfMaterials] b ON b.[ProductAssemblyID] = cte.[ComponentID]
INNER JOIN [Production].[Product] p ON b.[ComponentID] = p.[ProductID]
WHERE @CheckDate >= b.[StartDate]
AND @CheckDate <= ISNULL(b.[EndDate], @CheckDate)
)
-- Outer select from the CTE
SELECT b.[ProductAssemblyID]
,b.[ComponentID]
,b.[ComponentDesc]
,SUM(b.[PerAssemblyQty]) AS [TotalQuantity]
,b.[StandardCost]
,b.[ListPrice]
,b.[BOMLevel]
,b.[RecursionLevel]
FROM [BOM_cte] b
GROUP BY b.[ComponentID]
,b.[ComponentDesc]
,b.[ProductAssemblyID]
,b.[BOMLevel]
,b.[RecursionLevel]
,b.[StandardCost]
,b.[ListPrice]
ORDER BY b.[BOMLevel]
,b.[ProductAssemblyID]
,b.[ComponentID]
OPTION (MAXRECURSION 25)
END;
SET @logrowcount = CONVERT(VARCHAR(36), @@ROWCOUNT)
IF @logrowcount = '0'
BEGIN
SET @ReturnCode = 999
END
RETURN @ReturnCode
请有人指教。如何使它工作并返回返回码?
编辑:我在评论中问的最后一个问题是不是。我的问题格式不正确。
我不是要问有关如何获取结果集的一般性问题。我问我从语句中读取返回代码后如何获得结果集。
问题是我老板的存储过程正在返回一个代码,该代码除其他外可以告诉我结果集中是否需要获取数据。不幸的是,如果我使用statement.getInt()读取代码,则ResultSet对象被“关闭”,并且在获得返回代码说有数据I之后,由于ResultSet的关闭,ResultSet的getXXX()函数生成了一个例外。我实际上想问的是,是否有一种方法可以从CallableStatement中获取返回代码而不关闭ResultSet;或者相反,是否有一种方法可以在我抓住返回代码后重新打开ResultSet。提到的答案不能解决这个问题。
我的问题还意味着另外一个问题:我是否在CallableStatement API中发现错误?当然,这里没有任何地方回答该问题。