フォームのクエリがあるとします
SELECT * FROM MYTABLE WHERE MYCOL in (?)
そして、in への引数をパラメータ化したいと思います。
SQL自体を変更せずに複数のデータベースで機能する方法で、JavaでJDBCを使用してこれを行う簡単な方法はありますか?
私が見つけた最も近い質問は C# に関係していました.Java/JDBCに何か違うものがあるのではないかと思っています.
JDBCでこれを行う簡単な方法は確かにありません。一部のJDBCドライバーは、この句をサポートPreparedStatement#setArray()
しているようです。IN
どれなのかわからないだけです。
とを使用してヘルパーメソッドを使用し、句のプレースホルダーを生成し、String#join()
。を使用してループ内のすべての値を設定する別のヘルパーメソッドを使用できます。Collections#nCopies()
IN
PreparedStatement#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アイテムにこの制限があります。
大きな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は現在のバッチと同じです。完了したら、バッチのエントリを削除します。
これを行う標準的な方法は (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;
}
?
検索する値をできるだけ多く使用して SQL 文字列を作成することで、これを解決しました。
SELECT * FROM MYTABLE WHERE MYCOL in (?,?,?,?)
まず、ステートメントに渡すことができる配列タイプを探しましたが、すべての JDBC 配列タイプはベンダー固有です。だから私は倍数にとどまりました?
。
私の知る限り、コレクションをパラメーターとして処理するための JDBC の標準サポートはありません。List を渡すだけで、それが拡張されると便利です。
Spring の JDBC アクセスは、コレクションをパラメーターとして渡すことをサポートしています。これを安全にコーディングするためのインスピレーションを得るために、これがどのように行われるかを見ることができます。
JDBC パラメーターとしてのコレクションの自動拡張を参照してください。
(この記事では、最初に Hibernate について説明し、次に JDBC について説明します。)
私の試用版と成功を参照してください。リストのサイズには潜在的な制限があると言われています。リスト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);
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());
}
使用できるさまざまな代替アプローチがあります。
これらの詳細については、こちらをご覧ください。
私が考えることができる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