43

フォームのクエリがあるとします

SELECT * FROM MYTABLE WHERE MYCOL in (?)

そして、in への引数をパラメータ化したいと思います。

SQL自体を変更せずに複数のデータベースで機能する方法で、JavaでJDBCを使用してこれを行う簡単な方法はありますか?

私が見つけた最も近い質問は C# に関係していました.Java/JDBCに何か違うものがあるのではないかと思っています.

4

10 に答える 10

48

JDBCでこれを行う簡単な方法は確かにありません。一部のJDBCドライバーは、この句をサポートPreparedStatement#setArray()しているようです。INどれなのかわからないだけです。

とを使用してヘルパーメソッドを使用し、句のプレースホルダーを生成し、String#join()。を使用してループ内のすべての値を設定する別のヘルパーメソッドを使用できます。Collections#nCopies()INPreparedStatement#setObject()

public static String preparePlaceHolders(int length) {
    return String.join(",", Collections.nCopies(length, "?"));
}

public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException {
    for (int i = 0; i < values.length; i++) {
        preparedStatement.setObject(i + 1, values[i]);
    }
}

使用方法は次のとおりです。

private static final String SQL_FIND = "SELECT id, name, value FROM entity WHERE id IN (%s)";

public List<Entity> find(Set<Long> ids) throws SQLException {
    List<Entity> entities = new ArrayList<Entity>();
    String sql = String.format(SQL_FIND, preparePlaceHolders(ids.size()));

    try (
        Connection connection = dataSource.getConnection();
        PreparedStatement statement = connection.prepareStatement(sql);
    ) {
        setValues(statement, ids.toArray());

        try (ResultSet resultSet = statement.executeQuery()) {
            while (resultSet.next()) {
                entities.add(map(resultSet));
            }
        }
    }

    return entities;
}

private static Entity map(ResultSet resultSet) throws SQLException {
    Enitity entity = new Entity();
    entity.setId(resultSet.getLong("id"));
    entity.setName(resultSet.getString("name"));
    entity.setValue(resultSet.getInt("value"));
    return entity;
}

IN一部のデータベースでは、句の値の許容量に制限があることに注意してください。たとえば、Oracleでは1000アイテムにこの制限があります。

于 2010-05-18T22:09:52.213 に答える
15

大きなIN句(100を超える)の場合には誰も答えないので、JDBCでうまく機能するこの問題の解決策を紹介します。要するに、私はtmpテーブルのINをに置き換えます。INNER JOIN

私がしていることは、私がバッチIDテーブルと呼ぶものを作成することであり、RDBMSに応じて、それをtmpテーブルまたはメモリテーブルに作成する場合があります。

テーブルには2つの列があります。IN句のIDを持つ1つの列と、オンザフライで生成するバッチIDを持つ別の列。

SELECT * FROM MYTABLE M INNER JOIN IDTABLE T ON T.MYCOL = M.MYCOL WHERE T.BATCH = ?

選択する前に、指定されたバッチIDを使用してIDをテーブルに押し込みます。次に、元のクエリのIN句を、idsテーブルで一致するINNER JOINに置き換えるだけです。ここで、batch_idは現在のバッチと同じです。完了したら、バッチのエントリを削除します。

于 2012-06-20T12:33:06.143 に答える
9

これを行う標準的な方法は (Spring JDBC を使用している場合)、org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplateクラスを使用することです。

このクラスを使用すると、List を SQL パラメーターとして定義し、NamedParameterJdbcTemplate を使用して名前付きパラメーターを置き換えることができます。例えば:

public List<MyObject> getDatabaseObjects(List<String> params) {
    NamedParameterJdbcTemplate jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
    String sql = "select * from my_table where my_col in (:params)";
    List<MyObject> result = jdbcTemplate.query(sql, Collections.singletonMap("params", params), myRowMapper);
    return result;
}
于 2013-02-18T14:02:29.150 に答える
4

?検索する値をできるだけ多く使用して SQL 文字列を作成することで、これを解決しました。

SELECT * FROM MYTABLE WHERE MYCOL in (?,?,?,?)

まず、ステートメントに渡すことができる配列タイプを探しましたが、すべての JDBC 配列タイプはベンダー固有です。だから私は倍数にとどまりました?

于 2010-05-18T21:21:59.960 に答える
1

私の知る限り、コレクションをパラメーターとして処理するための JDBC の標準サポートはありません。List を渡すだけで、それが拡張されると便利です。

Spring の JDBC アクセスは、コレクションをパラメーターとして渡すことをサポートしています。これを安全にコーディングするためのインスピレーションを得るために、これがどのように行われるかを見ることができます。

JDBC パラメーターとしてのコレクションの自動拡張を参照してください。

(この記事では、最初に Hibernate について説明し、次に JDBC について説明します。)

于 2010-05-18T21:44:49.087 に答える
0

私の試用版と成功を参照してください。リストのサイズには潜在的な制限があると言われています。リストl=Arrays.asList(new Integer [] {12496,12497,12498,12499}); マップparam=Collections.singletonMap( "goodsid"、l);

    NamedParameterJdbcTemplate  namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(getJdbcTemplate().getDataSource());
    String sql = "SELECT bg.goodsid FROM beiker_goods bg WHERE bg.goodsid in(:goodsid)";
    List<Long> list = namedParameterJdbcTemplate.queryForList(sql, param2, Long.class);
于 2012-02-08T07:10:20.747 に答える
0

sormula はこれを簡単にします (例 4を参照):

ArrayList<Integer> partNumbers = new ArrayList<Integer>();
partNumbers.add(999);
partNumbers.add(777);
partNumbers.add(1234);

// set up
Database database = new Database(getConnection());
Table<Inventory> inventoryTable = database.getTable(Inventory.class);

// select operation for list "...WHERE PARTNUMBER IN (?, ?, ?)..."
for (Inventory inventory: inventoryTable.
    selectAllWhere("partNumberIn", partNumbers))    
{
    System.out.println(inventory.getPartNumber());
}
于 2012-02-16T19:20:00.903 に答える
0

使用できるさまざまな代替アプローチがあります。

  1. 単一クエリの実行 - 遅く、推奨されません
  2. ストアド プロシージャの使用 - データベース固有
  3. PreparedStatement Query の動的な作成 - パフォーマンスは良好ですが、キャッシングのメリットが少なく、再コンパイルが必要です
  4. PreparedStatement クエリで NULL を使用する - これは最適なパフォーマンスを実現する良いアプローチだと思います。

これらの詳細については、こちらをご覧ください。

于 2014-01-26T13:41:00.737 に答える
-2

私が考えることができる1つの方法は、java.sql.PreparedStatementと少しの陪審員の談合を使用することです

PreparedStatement prepareStmt = conn.prepareStatement("SELECT * FROM MYTABLE WHERE MYCOL in (?)");

... その後 ...

prepareStmt.setString(1, [文字列化されたパラメータ]);

http://java.sun.com/docs/books/tutorial/jdbc/basics/prepared.html

于 2010-05-18T21:34:55.433 に答える