Java中的参数化Oracle SQL查询?

5

我一直在尝试弄清楚为什么以下代码没有生成任何ResultSet数据:

String sql = "SELECT STUDENT FROM SCHOOL WHERE SCHOOL = ? ";
PreparedStatement prepStmt = conn.prepareStatement(sql);
prepStmt.setString(1, "Waterloo");
ResultSet rs = prepStmt.executeQuery();

另一方面,以下内容可以正常运行:
String sql = "SELECT STUDENT FROM SCHOOL WHERE SCHOOL = 'Waterloo' ";
PreparedStatement prepStmt = conn.prepareStatement(sql);
ResultSet rs = prepStmt.executeQuery();

SCHOOL的数据类型为CHAR(9个字节)。除了setString之外,我还尝试过:
String sql = "SELECT STUDENT FROM SCHOOL WHERE SCHOOL = ? ";
PreparedStatement prepStmt = conn.prepareStatement(sql);
String school = "Waterloo";
Reader reader = new CharArrayReader(school.toCharArray());
prepStmt.setCharacterStream(1, reader, 9);
prepStmt.setString(1, "Waterloo");
ResultSet rs = prepStmt.executeQuery();

我完全不知道接下来应该调查什么;Eclipse 调试器显示 SQL 查询在 setString 或 setCharacterStream 之后没有变化。我不确定是因为设置参数不起作用,还是调试器不能捕捉 PreparedStatement 的更改。

非常感谢任何帮助!谢谢!


有两件事情需要检查:1)如果您不使用一个列名与表名相同的表,是否仍然会发生这种情况?2)您确定正在正确地迭代结果集吗?如果您硬编码查询而不是使用参数,您是否会得到结果? - Jon Skeet
就我个人而言,你的第一个例子看起来很好。Jon可能在“School”表中的“School”列上有所发现-这不应该是一个问题,但是你的代码不应该失败... - Andrzej Doyle
只是出于好奇,尝试第一个例子(带有 ?)但将参数设置为带有尾随空格的 "Waterloo "。MySQL应忽略尾随空格,但也许驱动程序在这种情况下正在进行某些奇怪的操作。 - Jim Garrison
我尝试更改字段和表名以使其更易于理解,因此实际列名与表名不同。我想这样做适得其反了!下次需要构建更好的示例 =) - echoblaze
1个回答

10

我认为问题在于你的数据类型是CHAR(9),而“Waterloo”只有8个字符。 我假设这将返回期望的结果(使用LIKE和%)。或者添加缺失的空格。

String sql = "SELECT STUDENT FROM SCHOOL WHERE SCHOOL LIKE ? ";
PreparedStatement prepStmt = conn.prepareStatement(sql);
prepStmt.setString(1, "Waterloo%");
ResultSet rs = prepStmt.executeQuery();

如果你的字符串长度是可变的,最好使用varchar而不是char。这样PreparedStatement将按预期工作。

一个解决方法是使用Oracle特定的setFixedCHAR方法(但最好在可能的情况下更改数据类型为varchar)。

以下内容来自Oracle的PreparedStatement JavaDoc:


数据库中的CHAR数据被填充到列宽度。这导致在将字符数据绑定到SELECT语句的WHERE子句时使用setCHAR()方法存在限制 - WHERE子句中的字符数据必须也被填充到列宽度以在SELECT语句中产生匹配。如果您不知道列宽度,则尤其麻烦。

setFixedCHAR()可以解决此问题。该方法执行无填充比较。

注意:

  • 记得将准备好的语句对象强制转换为OraclePreparedStatement,以使用setFixedCHAR()方法。
  • 对于INSERT语句,不需要使用setFixedCHAR()。数据库总是在插入数据时自动将数据填充到列宽度。

以下示例演示了setString()、setCHAR()和setFixedCHAR()方法之间的差异。

// Schema is : create table my_table (col1 char(10));
//             insert into my_table values ('JDBC');
PreparedStatement pstmt = conn.prepareStatement
("select count() from my_table where col1 = ?");
ResultSet rs;

pstmt.setString (1, "JDBC");  // Set the Bind Value
rs = pstmt.executeQuery();    // This does not match any row
// ... do something with rs
CHAR ch = new CHAR("JDBC      ", null);
((OraclePreparedStatement)pstmt).setCHAR(1, ch); // Pad it to 10 bytes
rs = pstmt.executeQuery();     // This matches one row
// ... do something with rs
((OraclePreparedStatement)pstmt).setFixedCHAR(1, "JDBC");
rs = pstmt.executeQuery();     // This matches one row
// ... do something with rs

谢谢!我真希望我能改变数据类型,但它是受保护的数据库,我只能查询它。 - echoblaze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接