4

我有一个 SQL 语句,它在 MS Server Management Studio 中执行时有效,从 C# 提交时有效,但从 Java 提交时无效(1.6,使用 sqljdbc4.jar)。

基本问题似乎是选择表变量。继第一条评论之后,我已经使用更简单的示例完全重写了这个问题,以显示哪些有效,哪些无效。

以下查询:

DECLARE @IsLoadRaw as INT = ? 
DECLARE @PrimaryID as varchar(1000) = ?
--Declare temporary table to hold message IDs and fill according to Primary ID.
DECLARE @MessageIDs TABLE ( MessageID BIGINT )
SELECT MessageID FROM Messages WHERE PrimaryID = @PrimaryID

在 SQL Management Studio 和从 Java 提交时都可以使用。在这两种情况下,它都会返回一个带有两个 MessageID 的结果集(对于我用来测试的给定 PrimaryID 是正确的)。

以下查询:

DECLARE @IsLoadRaw as INT = ? 
DECLARE @PrimaryID as varchar(1000) = ?
--Declare temporary table to hold message IDs and fill according to Primary ID.
DECLARE @MessageIDs TABLE ( MessageID BIGINT );
INSERT @MessageIDs SELECT MessageID FROM Messages WHERE PrimaryID = @PrimaryID;
SELECT * FROM @MessageIDs;

在 SQL Management Studio 中工作,它返回具有相同两个 MessageID 的结果集。从 Java 提交时,它不返回任何结果集。

使我们使用@MessageIDs 的完整语句在通过ADO.NET 从C# 提交时起作用。我假设这里的第二个示例也可以。该问题与 Java 无关,似乎与使用表变量有关。由于代码看起来正确并在 SQL Management Studio 下运行,我对如何调试它感到困惑。

知道为什么这不适用于 Java 吗?当从 Java 提交时,我可以使用哪些工具来了解服务器对此查询的操作?

4

1 回答 1

7

我做了更多的挖掘并找到了答案:

INSERT @MessageIDs SELECT MessageID FROM Messages WHERE PrimaryID = @PrimaryID;

从 Java 提交时返回更新计数。从 C# 或 SQL 管理控制台提交时,它不会返回更新计数。我没想到会这样,所以花了一些时间才找到。

用于单步执行结果的 java APIexecute()令人困惑,没有可能的示例,而且我发现至少有一个不完全正确。我将解释我如何理解它的工作原理。

由于大多数语句都很简单,一改一选,因此 Statement 上有方便的执行方法,例如executeQuerry(),它返回一个结果集。大多数情况下都使用这些,这就是故事的结尾。

如果你有一个更复杂的语句,它做了几件事情,你调用execute()并返回一个事情列表。 INSERT, UPDATE, 和DELETE(我相信)返回修改的记录数。 SELECT返回一个结果集。执行复杂语句的结果是更新计数和结果集的列表,按执行顺序排列。然后,您编写逐个遍历此列表的代码,处理每个项目。

该声明

DECLARE @MessageIDs TABLE ( MessageID BIGINT )
INSERT @MessageIDs SELECT MessageID FROM Messages WHERE PrimaryID = @PrimaryID;
SELECT * FROM Messages WHERE MessageID IN (SELECT MessageID FROM @MessageIDs) ORDER BY MessageID;
SELECT * FROM Attrs WHERE MessageID IN (SELECT MessageID FROM @MessageIDs) ORDER BY MessageID;

返回 2 个结果集。在 java 中,并且出于我不知道的原因仅在 java 中,该INSERT @MessageIDs...语句返回一个更新计数,它是列表中的第一项。

用于此的 java API 令人困惑。Statement.execute() 和 Statement.getMoreResults() 返回:

  • true如果下一个结果是 ResultSet
  • false如果下一个结果是更新计数或没有更多结果

false有两层意思,不能解释为结果的结束。您还必须检查非零更新计数。

最终的功能代码最终看起来像这样:

List<DtaMessage> msgList = new ArrayList<DtaMessage>();
boolean isResult = stmt.execute();

// Skip over update counts.  
while (!isResult) {
    if (stmt.getUpdateCount() == 0)
        // End of results.
        return msgList;
    isResult = stmt.getMoreResults();
}


// Process first result set.
ResultSet rs = stmt.getResultSet();
while (rs.next())
{
    DtaMessage msg = PopulateMessage(rs, isLoadRaw);
    msgList.add(msg);
}
rs.close();

// Skip over update counts.
isResult = stmt.getMoreResults();
while (!isResult) {
    if (stmt.getUpdateCount() == 0)
        // end of results.
        return msgList;
    isResult = stmt.getMoreResults();
}

// Process second result set.
rs = stmt.getResultSet();
while (rs.next())
{
    // process.
}
rs.close();
return msgList;

尽管我的示例 SQL 没有执行任何会在两个结果集之间生成更新计数的操作,但此方法将处理来自多个不同 SQL 语句的结果,因此我添加了代码以跳过在某些情况下可能出现的更新日期计数。

于 2012-07-19T19:48:21.673 回答