29

管理スタジオと で機能するクエリexecuteUpdateは、同じexecuteUpdatereturnを返し-1ます。これは、見つけることができるドキュメントでは定義されていません。行数またはのみを返すはず0です。これは何を意味するのでしょうか?それが重要な場合、ドライバーは JDBC-ODBC ブリッジです。

例:

String query = "IF NOT EXISTS (SELECT * FROM animals WHERE animal_name ='" + a +"') INSERT INTO " + table + " (animal_name, animal_desc, species_id) VALUES ('" + a + "', '" + b + "', " + c + ")";
int result = statement.executeUpdate(query);
System.out.println(result);

クエリは機能します。行がデータベースに追加されると、-1 が返されるのは奇妙なことですが、ドキュメントには 0 または行数のみが返されると記載されています (修正済み)。

アップデート:

これを Management Studio で実行すると、「コマンドが正常に完了しました」という結果になります。

IF NOT EXISTS (SELECT * FROM animals WHERE animal_name = 'a') 
INSERT INTO animals(animal_name, animal_desc, species_id) VALUES ('a', 'a', 1)

これは、何も返さないため、メソッドが 0 を返す必要があることを意味するはずですよね?

4

5 に答える 5

27

実行されたステートメントは実際には DML (例: UPDATEINSERTまたは) ではなく、DML を含むEXECUTET-SQL の一部であるため、更新クエリとして扱われていないと思われます。

JDBC 4.1 仕様のセクション 13.1.2.3 には、次のような記述があります (解釈がかなり難しい):

メソッドexecuteが true を返すgetResultSetと、ResultSet オブジェクトを取得するためにメソッドが呼び出されます。executefalse を返す 場合、メソッドgetUpdateCountは int を返します。この数値が 0 以上の場合は、ステートメントによって返された更新カウントを示します。-1 の場合、これ以上結果がないことを示します。

executeUpdate()この情報を考えると、 は内部的に を実行しexecute()、次に (返されるように)の値を返すexecute()と思います。この場合、JDBC 仕様に従って、 が返されます。falsegetUpdateCount()-1

これは、1) Javadoc forが次のようにStatement.executeUpdate()述べているという事実によってさらに裏付けられています。

戻り値: (1) SQL データ操作言語 (DML) ステートメントの行数、または (2) 何も返さない SQL ステートメントの場合は 0

2) Statement.getUpdateCount()の Javadoc で次のように指定されていること:

更新カウントとしての現在の結果。現在の結果が ResultSet オブジェクトであるか、それ以上結果がない場合は -1

明確にするためにexecuteUpdate()、動作の Javadoc を考えると、おそらく間違っていますが、説明することはできます。

また、私が他の場所でコメントしたように、-1 は単に何かが変更された可能性があることを示している可能性があります。実行される SQL)。

于 2012-09-13T17:57:32.183 に答える
10

そのため、4 年後、Microsoft は Github で JDBC ドライバーをオープンソース化しました今日、この質問に関する通知を受け取り、行って調べてみたところ、ここで犯人を見つけたと思いますmssql-jdbc/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java:1713.

基本的に、ドライバーは、SQL Server が返す内容が明確な結果セットでない場合に理解しようとします。コメントによると、次のようになります。

  1. 最初にエラーを確認してください。(1669年)

  2. エラーではありません。結果セットですか?(1680年)

  3. エラーまたは結果セットではありません。T-SQL ステートメントの結果でしょうか。つまり、次のいずれかです。

    • (INSERT、UPDATE、または DELETE から) 影響を受けた行数の正のカウント、
    • 影響を受ける行がないことを示すゼロ、またはステートメントが DDL であったことを示すゼロ、または
    • -1 は、ステートメントが成功したが、利用可能な更新カウント情報がないことを示します(バッチ更新カウント配列の Statement.SUCCESS_NO_INFO に変換されます)。(1706年)
  4. 上記のどれでもない。ここで最後のチャンスです... 上記のパーサーに入ると、moreResults が最初は true であることがわかりました。moreResults が false である場合は、DONE トークン (DONE (FINAL) または DONE (バッチの RPC)) をヒットします。これは、バッチが全体的に成功したことを示しますが、個々のステートメントの更新カウントに関する情報がないことを示します。これは、更新カウントがないことを除いて、上記の最後のケースに似ています。つまり、成功した結果 (true を返す) がありますが、それに関する他の情報はありません (updateCount = -1)。(1693年)

  5. ここに到達する唯一の方法 (moreResults は依然として true ですが、明らかな結果はありません) は、TDSParser が実際に 何も解析しなかった場合です。つまり、応答で EOF に達しています。その場合、本当にこれ以上の結果はありません。終わったね。(1717年)

(私のものを強調)

ですから、あなたたちは最終的に正しかったのです。SQL は、影響を受ける行数を単純に判断できず、デフォルトで-1. :)

于 2016-11-21T08:58:37.427 に答える
5

これもどこかで見たことがありませんが、私の本能は、これがIFステートメント全体の実行を妨げたことを意味するということです。

が渡されるデータベースでステートメントを実行してみてくださいIF

また、結果を変更する可能性のあるトリガーが含まれているかどうかも確認してください。

[編集]この関数が を返してはならないという標準がある場合、これは強制-1されません。Java には事前条件と事後条件がありません。JDBC ドライバーは乱数を返す可能性があり、それを止める方法はありませんでした。

なぜこれが起こるのかを知ることが重要な場合は、すべての実行パス (つまり、 がIF返されるパスfalseとそれが返されるパス) を試すまで、別のデータベースに対してステートメントを実行しますtrue

それほど重要でない場合は、Microsoft のエンジニアによる "巧妙なトリック" としてマークし、次回自分が巧妙になりたいと思ったときに、どれだけ気に入ったかを思い出してください。

于 2012-09-13T07:15:06.230 に答える
5

DB2 for z/OS サーバーに対する executeUpdate ステートメントの場合、返される値は、実行中の SQL ステートメントのタイプによって異なります。

INSERT、UPDATE、または DELETE ステートメントなど、更新カウントを持つことができる SQL ステートメントの場合、戻り値は影響を受ける行の数です。かもね:

正の数 (正の数の行が操作によって影響を受け、操作がセグメント化された表スペースでの一括削除ではない場合)。

操作によって影響を受ける行がない場合は 0。

操作がセグメント化された表スペースでの一括削除の場合は -1。

DB2 CALL ステートメントの場合、DB2 データベース サーバーは影響を受ける行の数を判別できないため、値 -1 が返されます。CALL ステートメントの getUpdateCount または getMoreResults への呼び出しも -1 を返します。その他の SQL ステートメントの場合、値 -1 が返されます。

于 2012-09-13T07:49:09.303 に答える
4

これは、なぜそれがそのようになるべきかを説明していませんが、なぜそれが起こり得るのかを説明しています。次のバイトコードは、コンストラクター-1の内部updateCountフラグに設定されます。SQLServerStatement

// Method descriptor #401 (Lcom/microsoft/sqlserver/jdbc/SQLServerConnection;II)V
// Stack: 5, Locals: 8
SQLServerStatement(
  com.microsoft.sqlserver.jdbc.SQLServerConnection arg0, int arg1, int arg2) 
throws com.microsoft.sqlserver.jdbc.SQLServerException;

// [...]

34 aload_0 [this]
35 iconst_m1
36 putfield com.microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

ここで、考えられるすべての制御フローを分析するわけではありませんが、これは内部のデフォルトの初期化値であり、何らかの形でクライアントコードにリークします。これは他の方法でも行われることに注意してください。

// Method descriptor #383 ()V
// Stack: 2, Locals: 1
final void resetForReexecute() 
throws com.microsoft.sqlserver.jdbc.SQLServerException;

// [...]

10 aload_0 [this]
11 iconst_m1
12 putfield com.microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

// Method descriptor #383 ()V
// Stack: 3, Locals: 3
final void clearLastResult();
0 aload_0 [this]
1 iconst_m1
2 putfield com.microsoft.sqlserver.jdbc.SQLServerStatement.updateCount:int [27]

言い換えれば、あなたはおそらく-1と同じであると解釈しても安全です0。この結果値に依存している場合は、安全を確保し、次のようにチェックを行ってください。

// No rows affected
if (stmt.executeUpdate() <= 0) {
}
// Rows affected
else {
}

更新Mark Rotteveelの回答を読んでいる間、私は彼に同意する傾向があります。これは、 「不明な更新カウント」-1のJDBC準拠の値であると想定しています。これが関連するメソッドのJavadocに文書化されていない場合でも、JDBC仕様の13.1.2.3章「不明または複数の結果を返す」に文書化されています。この場合、このステートメントはSQL標準に準拠していないため、ステートメントには「不明な更新カウント」があると言えます。IF .. INSERT ..

于 2012-09-13T07:47:54.943 に答える