通过 jdbc 通过准备好的语句传递 SQL 命令时出错
Posted
技术标签:
【中文标题】通过 jdbc 通过准备好的语句传递 SQL 命令时出错【英文标题】:Error in passing SQL command through a prepared statement via jdbc 【发布时间】:2012-06-06 21:00:40 【问题描述】:我正在尝试创建程序在运行时获取行数和列数的表。
代码如下:
String sql =
"CREATE TABLE if not exists itemset (?";
up1 = con.prepareStatement(sql);
for(int j=1; j < ccolumns; j++)
sql += ",?";
sql += ")";
System.out.println(sql);
for(int j=1; j < ccolumns+1; j++)
System.out.println(j);
up1.setString(j, "item"+j+" TINYINT(10)");
up1.executeQuery();
错误是
Parameter index out of range (2 > number of parameters, which is 1)
在第二次迭代时出现在 setString 行中
【问题讨论】:
也许你应该调用“prepare”在你完成构建 SQL 字符串 ;)? PreparedStatement 不应用于 CREATE TABLE sql。 【参考方案1】:尝试移动
up1 = con.prepareStatement(sql);
之后
System.out.println(sql);
【讨论】:
这确实解决了之前的问题,但现在它给出了一个新问题对于5的ccolumns输入,sql语句似乎已更改为''item1 TINYINT(10)','item2 TINYINT (10)','item3 TINYINT(10)','item4 TINYINT(10)',' 必须有 5 个而不是 4 个(第二个循环正在迭代 5 次)【参考方案2】:虽然我没有验证,但我相信 Andriy 的回答是正确的。此外,您可能需要考虑使用StringBuilder 进行字符串累积,因为它们的重量较轻。下面更新了代码。
StringBuilder sql = new StringBuilder("CREATE TABLE if not exists itemset (?");
for (int j = 1; j < ccolumns; j++)
sql.append(",?");
sql.append(")");
System.out.println(sql.toString());
up1 = con.prepareStatement(sql.toString());
for (int j = 1; j < ccolumns + 1; j++)
System.out.println(j);
up1.setString(j, "item" + j + " TINYINT(10)");
up1.executeQuery();
【讨论】:
【参考方案3】:您要修复的第一件事是,当您要更改它时,请不要使用String
实例。 String
实例是不可变的,当您修改已创建的 String
时,会创建新的修改实例并且它不是免费的。
您应该为此使用StringBuilder
,它具有允许修改它而无需创建新实例的实例方法。我建议您在修改String
时始终使用StringBuilder
。其次,您致电con.prepareStatement(sql)
,然后修改其sql字段。这不好不是吗?
所以只有在你使用 String 之后才添加它。
String sql =
"CREATE TABLE if not exists itemset (?";
for(int j=1; j < ccolumns; j++)
sql += ",?";
sql += ")";
System.out.println(sql);
up1 = con.prepareStatement(sql);
for(int j=1; j < ccolumns+1; j++)
System.out.println(j);
up1.setString(j, "item"+j+" TINYINT(10)");
up1.executeQuery();
你不能用给定的String
调用prepareStatement
然后修改它。
但更清洁和更快尝试这样做
StringBuilder sqlStatement = new StringBuilder(
"CREATE TABLE if not exists itemset (?");
for(int j=1; j < ccolumns; j++)
sqlStatement.append(",?");
sqlStatement.append(")");
up1 = con.prepareStatement(sqlStatement.toString());
for(int j=1; j < ccolumns+1; j++)
System.out.println(j);
up1.setString(j, "item"+j+" TINYINT(10)");
up1.executeQuery();
【讨论】:
@PhilippReichart 抱歉,我看到后立即更换错误,已更正。 错误是在字符串之前给出preparestatement,通过使用StringBuilder它仍然给出了我在回复andriy时提到的问题,无论如何我不知道StringBuilder谢谢【参考方案4】:PreparedStatement
不能用于 DDL 查询,例如问题中的 CREATE TABLE
。
传递给setString()
的值在生成的 SQL 中被转义,导致发送到数据库的查询无效。
当只给出列数时,只需创建 CREATE TABLE 语句(如其他人建议的那样使用StringBuilder
)并使用普通的Statement
执行它,不需要PreparedStatement
:
String getCreateTableSql(int columns)
StringBuilder sql = new StringBuilder("CREATE TABLE IF NOT EXISTS itemset (");
for (int i = 0; i < columns; i++)
if (i > 0)
sql.append(", ");
sql.append("item").append(i + 1).append(" TINYINT(10)");
sql.append(")");
return sql.toString();
对于 4 列,这将输出:
CREATE TABLE IF NOT EXISTS itemset (item1 TINYINT(10), item2 TINYINT(10), item3 TINYINT(10), item4 TINYINT(10))
【讨论】:
是的,简单的声明是有效的,但我想尝试准备声明。无论如何,谢谢以上是关于通过 jdbc 通过准备好的语句传递 SQL 命令时出错的主要内容,如果未能解决你的问题,请参考以下文章
当它们包含 ROW_NUMBER() 时,JDBC-driver / SQL Server 总是重新编译我准备好的语句