web-dev-qa-db-ja.com

Statement.executeUpdate()が-1を返すとはどういう意味ですか?

管理スタジオとexecuteUpdateで機能するクエリは、同じexecuteUpdate-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);

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

更新:

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を返すことを意味するはずです、正しいですか?

26
ldam

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

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

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

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

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

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

  5. ここに到達する唯一の方法(moreResultsはまだtrueですが、どのような種類の明らかな結果もありません)は、TDSParserが実際にanythingを解析しなかった場合です。つまり、応答ではEOFにいます。その場合、これ以上結果はありません。完了です。(1717年)

(エンファシス鉱山)

だからあなたたちは最終的に正しかった。 SQLは、影響を受ける行数を単純に知ることができず、デフォルトでは-1。 :)

7
ldam

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

JDBC 4.1仕様のセクション13.1.2.3には、何か(むしろ解釈が難しい)が記載されています。

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

この情報を考えると、executeUpdate()は内部でexecute()を実行し、execute()falseを返すので、値を返すと思います。 getUpdateCount()の場合、この場合-JDBC仕様に従って-_-1_を返します。

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

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

そして2) Statement.getUpdateCount() のJavadocが指定すること:

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

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

また、私が他の場所でコメントしたように、-1は単に何かを示しているかもしれません:何かが変更されたかもしれませんが、単に知らないか、正確な数の変更を与えることができません(例えば、この例ではT-実行されるSQL)。

27
Mark Rotteveel

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

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

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

操作の影響を受ける行がない場合は0。

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

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

5
Sachin Mhetre

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

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

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

[EDIT]標準によると この関数は-1、これはenforceしません。 Javaには事前条件と事後条件はありません。JDBCドライバーは乱数を返す可能性があり、それを停止する方法がありませんでした。

これが発生する理由を知ることが重要な場合は、すべての実行パス(つまり、IFfalseを返すものとtrueを返すもの)を試行するまで、別のデータベースに対してステートメントを実行します。

それほど重要でない場合は、Microsoftエンジニアによって「巧妙なトリック」としてマークを外し、次回自分が賢くなりたいと感じたときにどれだけ気に入ったか覚えておいてください。

5
Aaron Digulla

これは、なぜそれがそのようになるべきかを説明するものではありませんが、なぜそれが起こり得るのかを説明します。次のバイトコードは、-1updateCountコンストラクターの内部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]

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

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

[〜#〜] update [〜#〜]Mark Rotteveelの答え を読みながら、私は彼に同意する傾向があり、 -1 "unknown update counts"のJDBC準拠の値であると仮定します。関連するメソッドのJavadocに文書化されていない場合でも、 JDBC仕様、13.1.2.3未知または複数の結果を返す に文書化されています。この場合、IF .. INSERT ..ステートメントには "unknown update count"があると言えます。このステートメントはとにかくSQL標準に準拠していないためです。

4
Lukas Eder