web-dev-qa-db-ja.com

プリペアドステートメントを使用したテーブル名の設定

プリペアドステートメントを使用してデータを選択するテーブル名を設定しようとしていますが、クエリを実行するとエラーが発生し続けます。

エラーとサンプルコードを以下に示します。

[Microsoft][ODBC Microsoft Access Driver] Parameter 'Pa_RaM000' specified where a table name is required.



private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [?]"; //?=date
public Execute(String reportDate){
    try {

        Class.forName("Sun.jdbc.odbc.JdbcOdbcDriver");
        Connection conn = DriverManager.getConnection(Display.DB_MERC);
        PreparedStatement st = conn.prepareStatement(query1);
        st.setString(1, reportDate);
        ResultSet rs = st.executeQuery();

これを引き起こしている可能性があるものについて何か考えはありますか?

27
Brandon

テーブル名をパラメータとして使用することはできません。ハードコーディングする必要があります。したがって、次のようなことができます。

private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [" + reportDate + "?]";
31
camickr

これは回避策で技術的には可能ですが、非常に悪い習慣です。

String sql = "IF ? = 99\n";
sql += "SELECT * FROM first_table\n";
sql += "ELSE\n";
sql += "SELECT * FROM second_table";
PreparedStatement ps = con.prepareStatement(sql);

そして、first_tableから選択する場合は、次のようにパラメータを設定します。

ps.setInt(1, 99);

または、そうでない場合は、別の設定に設定します。

2
mypetlion

これは役立つかもしれません:

public ResultSet getSomething(String tableName) {

PreparedStatement ps = conn.prepareStatement("select * from \`"+tableName+"\`");
ResultSet rs = ps.executeQuery();
}
0
Tanvir Singh

SQLインジェクションに対して脆弱ではないのソリューションが必要な場合は、必要なすべてのテーブルに対してクエリを複製する必要があります。

final static String QUERIES = {
    "SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ...",
    "SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ...",
    "SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ...",
    ...
};

はい:クエリは重複しており、テーブル名のみが異なります。

ここで、テーブルに適合するクエリを選択するだけです。お気に入り

...
PreparedStatement st = conn.prepareStatement(QUERIES[index]);
...

このアプローチは、JPA、Hibernateなどで使用できます...

より詳細なアプローチが必要な場合は、次のような列挙型の使用を検討してください。

enum AQuery {
    Table1("SELECT x FROM Table1 x WHERE a=:a AND b=:b AND ..."),
    Table2("SELECT x FROM Table2 x WHERE a=:a AND b=:b AND ..."),
    Table3("SELECT x FROM Table3 x WHERE a=:a AND b=:b AND ..."),
    ...

    private final String query;
    AQuery(final String query) {
        this.query = query;
    }

    public String getQuery() {
        return query;
    }
}

次に、いずれかのインデックスを使用します

String sql = AQuery.values()[index].getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...

またはテーブル名を使用します

String sql = AQuery.valueOf("Table1").getQuery();
PreparedStatement st = conn.prepareStatement(sql);
...
0
bebbo

多くの人が言っているように、テーブル名にステートメントパラメータを使用することはできず、条件の一部として変数にのみ使用できます。

(少なくとも)2つのテーブル名を持つ可変テーブル名があるという事実に基づいて、格納しているエンティティを受け取り、プリペアドステートメントを返すメソッドを作成するのがおそらく最善でしょう。

PreparedStatement p = createStatement(table);
0
Damien Allison