1

データベースを通じてクエリを実行するときに、システムの Java Bean が SQL IN 句を使用できるように取り組んでいますが、複雑な問題が発生しています。

次の一般的なパターンで、PreparedStatement の SQL クエリを作成しています。

select [column names] 
from [table name]
where [a column name] IN (?, ? , ?, ..., ?)

..., は、ユーザーが IN 句に組み込むことを決定した値の数に応じて、任意の数の ? を表します。これらをクエリ文字列に入れるためにループを実行します。

ここから、PreparedStatement の setString( idx, String ) メソッドを使用して、値のリストを繰り返し処理し、インデックス 1 - 値の数から実行します。

PreparedStatement は executeQuery() メソッドを介してクエリを実行し、返された ResultSet は正しくないようです。

4 つの値を使用する特定のインスタンスで、PreparedStatement のクエリを SQL に取り、それぞれを置き換えると、? 「 」の正確な値を使用すると、3 つの結果が得られます (値の 1 つが意図的に DB にないため)。

一方、ResultSet のセットには 1 行しかなく、その行は常に最初の ? IN 句のパラメーター。

IN 句を ([列名] = ? OR [列名] = ? ... OR 列名] = ?) で偽造しようとしましたが、ここでも同じ問題が発生します。

ここで何が起こっているのですか?ところで、Oracle データベースに接続します。

ログ:

2010-02-10 11:16:28,505 DEBUG  basic.BasicCursor - Preparing statement SELECT MERCHANT_ID, M_NAME, M_AUTHEN, M_ADMIN_AUTHEN, M_CONTACT_ADDR, M_PAYMENT_ADDR, M_HAS_MPROXY, M_DISABLED, M_FREETEXT, TXN_ID, M_TAX_NAME, M_TAX_RATE, MERCHANT_PARENT_ID, MERCHANT_ROOT_ID, RESERVED_1, RESERVED_2, RESERVED_3, RESERVED_4, EMAIL, LOGICAL_TYPE, CHANNEL_MASK FROM MERCHANT0 WHERE MERCHANT_ID IN (?, ?, ?, ?)  ORDER BY MERCHANT_ID
2010-02-10 11:16:28,505 DEBUG  basic.BasicCursor - Adding string  to slot 1: 6172222222
2010-02-10 11:16:28,505 DEBUG  basic.BasicCursor - Adding string  to slot 2:  6177740603
2010-02-10 11:16:28,505 DEBUG  basic.BasicCursor - Adding string  to slot 3:  6177740602
2010-02-10 11:16:28,505 DEBUG  basic.BasicCursor - Adding string  to slot 4:  6172441111
2010-02-10 11:16:28,512 DEBUG  basic.BasicCursor - scanCursor() calling... checking for next row. Current row is : 0
2010-02-10 11:16:28,512 DEBUG  basic.BasicCursor - scanCursor() called, hit
2010-02-10 11:16:28,512 DEBUG  basic.BasicCursor - scanCursor() got object 6172222222
2010-02-10 11:16:28,512 DEBUG  basic.BasicCursor - scanCursor() calling... checking for next row. Current row is : 1
2010-02-10 11:16:28,512 DEBUG  basic.BasicCursor - scanCursor() called, not hit
2010-02-10 11:16:28,505 DEBUG  basic.BasicCursor - The size of variables list = 4

編集: PreparedStatement の問題が見つかりました。それを理解することに興味がある人への演習として残しておきます。上記のログ ステートメントに表示されます。残念ながら、現在、私の問題は、現在期待されている ResultSet からの行をとにかく 1 つのレコードのみを表示するように制限する、私たちが持っている厄介な独自のコードにカスケードされています。はぁ

4

2 に答える 2

3
  • 完全に構築されたクエリを再確認し、それが実際に期待どおりであることを比較します
  • インデックスと文字列に異なる値で実際に呼び出していること、および同じ値を何度も使用していないことを再確認しsetString()てください
  • next()ループ反復ごとに ResultSet を複数回呼び出していないことを再確認してください。
  • 編集: 以下System.out.println()を確認 (および場合によっては投稿) します。
    • 完全な SQL クエリ文字列
    • toString()新しく作成されたPreparedStatement
    • setString()各呼び出しと呼び出すたびtoString()の両方のパラメーターPreparedStatementsetString()
    • next()呼び出すたびの戻り値
于 2010-02-10T15:55:22.713 に答える
0

それで、あなたはこの構造を使いましたか?

private static final String SQL = "SELECT * FROM MERCHANT0 WHERE MERCHANT_ID IN (%s)";

public List<Merchant> list(List<Long> ids) {
    StringBuilder placeHolders = new StringBuilder();
    for (int i = 0; i < ids.size(); i++) {
        placeHolders.append("?");
        if (i + 1 < ids.size()) {
            placeHolders.append(",");
        }
    }
    String sql = String.format(SQL, placeHolders.toString());

    // ...

    try {
        // ...

        preparedStatement = connection.prepareStatement(SQL);
        for (int i = 0; i < ids.size(); i++) {
            preparedStatement.setLong(i + 1, ids.get(i));
        }
        resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            Long id = resultSet.getLong("MERCHANT_ID");
            System.out.println(id); // Should print all of the `ids`.
        }

        // ...

INOracle では句内の値が約 1000 に制限されていることを除けば、これは機能するはずです。

于 2010-02-10T16:15:02.087 に答える