4

MS Server Management Studioで実行すると機能し、C#から送信すると機能するが、Java(1.6、sqljdbc4.jarを使用)から送信すると機能しないSQLステートメントがあります。

基本的な問題は、テーブル変数を選択することのようです。最初のコメントのフォローアップとして、簡単な例を使用してこの質問を完全に書き直し、何が機能し、何が機能しないかを示しました。

次のクエリ:

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から送信された場合の両方で機能します。どちらの場合も、2つの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で動作し、同じ2つのMessageIDを持つ結果セットを返します。Javaから送信された場合、結果セットは返されません。

@MessageIDsを使用する完全なステートメントは、C#からADO.NET経由で送信された場合に機能します。ここの2番目のサンプルも同様に機能すると思います。この問題はJavaに限定されており、テーブル変数の使用に関連しているようです。コードは正しく表示され、SQL Management Studioで実行されるため、これをデバッグする方法に戸惑います。

これがJavaから機能しない理由はありますか?Javaから送信されたときに、サーバーがこのクエリで何を行っているかを理解するために、どのツールを使用できますか?

4

1 に答える 1

7

私はもう少し発掘を行い、答えを見つけました:

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

Javaから送信されると、更新カウントが返されます。C#またはSQL Management Consoleから送信された場合、更新カウントは返されません。私はこれを予期していなかったので、見つけるのに少し掘り下げました。

これの結果をステップスルーするためのJavaAPIexecute()は混乱を招き、例はなく、少なくとも1つは完全に正しくありませんでした。これが機能することを私がどのように理解しているかを説明します。

executeQuerry()ほとんどのステートメントは単純で、1つの変更または1つの選択であるため、結果セットを返す、などの便利な実行メソッドがステートメントにあります。ほとんどの場合、これらを使用し、それで話は終わりです。

いくつかのことを実行するより複雑なステートメントがある場合は、呼び出し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...ステートメントは更新カウントを返します。これはリストの最初の項目です。

このためのJavaAPIは紛らわしいです。Statement.execute()およびStatement.getMoreResults()は次を返します。

  • true次の結果がResultSetの場合
  • false次の結果が更新カウントであるか、それ以上の結果がない場合

false2つの意味があり、結果の終わりであると解釈することはできません。ゼロ以外の更新カウントも確認する必要があります。

最終的に機能するコードは、次のようになりました。

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は、2つの結果セット間の更新カウントを生成するものは何もしませんが、このメソッドはいくつかの異なるSQLステートメントからの結果を処理するため、場合によっては表示される可能性のある日付カウントをスキップするコードを追加しました。

于 2012-07-19T19:48:21.673 に答える