31

我正在尝试使用准备好的语句来设置表名以从中选择数据,但是在执行查询时我不断收到错误消息。

错误和示例代码如下所示。

[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();

关于可能导致这种情况的任何想法?

4

7 回答 7

39

表名不能用作参数。它必须是硬编码的。因此,您可以执行以下操作:

private String query1 = "SELECT plantID, edrman, plant, vaxnode FROM [" + reportDate + "?]";
于 2009-07-30T18:33:11.137 回答
2

这在技术上是可行的解决方法,但非常糟糕的做法。

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);

或者,如果没有,您将其设置为其他内容。

于 2017-07-22T00:14:19.410 回答
2

如果您需要一个不易受到 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);
...
于 2019-08-13T09:36:38.850 回答
0

正如许多人所说,您不能将语句参数用于表名,只能将变量用作条件的一部分。

基于您有一个带有(至少)两个表名的变量表名这一事实,也许最好创建一个方法来获取您正在存储的实体并返回一个准备好的语句。

PreparedStatement p = createStatement(table);
于 2016-05-09T16:48:51.367 回答
-1

这可能会有所帮助:

public ResultSet getSomething(String tableName) {

PreparedStatement ps = conn.prepareStatement("select * from \`"+tableName+"\`");
ResultSet rs = ps.executeQuery();
}
于 2019-06-17T15:13:10.773 回答
-2

我不确定您是否可以使用 PreparedStatement 来指定表的名称,只是某些字段的值。无论如何,您可以尝试相同的查询,但没有括号:

"SELECT plantID, edrman, plant, vaxnode FROM ?"
于 2009-07-30T18:34:45.097 回答
-3
String table="pass"; 

String st="select * from " + table + " ";

PreparedStatement ps=con.prepareStatement(st);

ResultSet rs = ps.executeQuery();
于 2014-01-31T10:28:09.157 回答