1

データベーステーブルから削除したい主キー値のセットを生成するコードがあります。

long[] keysToDelete = { 0, 1, 2, 3 };

そして、PreparedStatementを使用して同等のものを実行したいと思います

DELETE FROM MyTable WHERE myPrimaryKey IN (0, 1, 2, 3);

どのようにアイデアはありますか?

4

3 に答える 3

5

2つのステップ:

  1. 適切な数のパラメーターを使用して、PreparedStatementSQL文字列を作成します。
  2. 値の配列をループし、それぞれをそのパラメーターにバインドします。

残念ながら、配列を一度にバインドする良い方法はありません。

于 2009-01-15T19:12:31.617 に答える
1

このようなマルチパラメータクエリを動的に生成するクラスを作成しました。現在、(書き込みの速さのために)いくつかの制限があり、徹底的にテストされていませんが、始めるのに良い方法かもしれません。制限:

  • 1つのマルチ引数パラメーターのみを処理します(??)
  • 引用符内の疑問符をパラメータとして誤って認識します
  • APIはきれいではありませんが、代替手段は、多くの状態管理を備えた完全なPreparedStatementデコレーターを作成することでした。これは、私が喜んで投入するよりも多くの作業でした。

ソース:

/**
 * A PreparedStatement decorator that can bind a set of arguments
 *
 * A specialized ?? placeholder in a string can be bound to a set of
 * values instead of just single values. Currently, only one such
 * specialized placeholder is supported, and you must bind it before
 * obtaining the prepared statement.
 *
 * If you want to bind additional values to the PreparedStatement after
 * producing it, you must run the parameter index through the param()
 * method.
 *
 * Example use:
 *
 * 
 *     MultiValueBinder binder = new MultiValueBinder(
 *          "UPDATE table SET value = ? WHERE id IN (??)", conn);
 *     binder.setInts(myIds);
 *
 *     PreparedStatement stmt = binder.statement();
 *     stmt.setString(binder.param(1), "myValue");
 *
 *     ResultSet rs = stmt.executeQuery();
 *
 * Note: this class is not robust against using question marks in literal
 * strings. Don't use them :).
 */
public class MultiValueBinder {
    private Connection connection;
    private PreparedStatement statement;
    private String sql;

    private int argumentsBefore = 0;
    private int setSize         = 0;

    public MultiValueBinder(String sql, Connection connection) {
        this.sql        = sql;
        this.connection = connection;
    }

    /**
     * Bind a collection of integers to the multi-valued argument
     */
    public void setInts(Collection<Integer> ints) throws SQLException {
        explodeQuery(ints.size());
        buildStatement();
        try {

            int i = 0;
            for (Integer integer: ints)
                statement.setInt(1 + argumentsBefore + i++, integer);

        } catch (Exception ex) {
            cleanStatement();
            throw (ex instanceof SQLException) ? (SQLException) ex : new SQLException(ex);
        }
    }

    /**
     * Bind a collection of strings to the multi-valued argument
     */
    public void setStrings(Collection<String> strings) throws SQLException {
        explodeQuery(strings.size());
        buildStatement();
        try {

            int i = 0;
            for (String str: strings)
                statement.setString(1 + argumentsBefore + i++, str);

        } catch (Exception ex) {
            cleanStatement();
            throw (ex instanceof SQLException) ? (SQLException) ex : new SQLException(ex);
        }
    }

    /**
     * Explode the multi-value parameter into a sequence of comma-separated
     * question marks.
     */
    private void explodeQuery(int size) throws SQLException {
        int mix = sql.indexOf("??");
        if (mix == -1) throw new SQLException("Query does not contain a multi-valued argument.");
        if (size == 0) throw new SQLException("Can't bind an empty collection; generated SQL won't parse.");

        // Count the number of arguments before the multi-marker
        argumentsBefore = 0;
        for (int i = 0; i < mix; i++) {
            if (sql.charAt(i) == '?') argumentsBefore++;
        }
        setSize = size;

        // Generate the exploded SQL query
        StringBuilder sb = new StringBuilder(sql.substring(0, mix)); // Start
        for (int i = 0; i < setSize; i++) {                          // ?, ?, ...
            if (i > 0) sb.append(", ");
            sb.append('?');
        }
        sb.append(sql.substring(mix + 2));                           // Remainder
        sql = sb.toString();
    }

    /**
     * Create the statement if it hasn't been created yet
     */
    private void buildStatement() throws SQLException {
        if (statement != null) return;
        if (sql.contains("??"))
            throw new SQLException("Multi-valued argument not bound yet.");
        statement = connection.prepareStatement(sql);
    }

    private void cleanStatement() {
        if (statement != null) {
            try {
                statement.close();
            } catch (Exception ex) {
                /* Ignore */
            }
            statement = null;
        }
    }

    public PreparedStatement statement() throws SQLException {
        buildStatement();
        return statement;
    }

    /**
     * Transform the 1-based-index of the given argument before query expansion
     * into the index after expansion.
     *
     * The ?? placeholder takes up one index slot.
     */
    public int param(int ix) {
        if (ix <= argumentsBefore) return ix;
        if (ix == argumentsBefore + 1)
            throw new RuntimeException(ix + " is the index of the multi-valued parameter.");
        return argumentsBefore + 1 + setSize;
    }
}
于 2011-01-13T13:01:53.747 に答える
0

完全にはわかりませんが、これは役立つ可能性があります。

PreparedStatement pstmt = Connection.prepareStatement("DELETE FROM MyTable WHERE myPrimaryKey IN (?)");
pstmt.setArray(1, idArray);
于 2009-01-15T19:28:41.800 に答える