我正在代码中使用临时表,以便在[SQL Server,Java中使用某些原因]。我正在使用Java中的Stament对象执行SQL查询。但是,最近我决定使用PreparedStatement以避免注入。
我的问题是,当使用PreparedStatement创建临时表时,无法再次使用相同的Prepared语句到达它。这是一个简单的例子:
sql = "select * into #someTable from (select someColumns from someOtherTable where smth = ? and smth2 = ?)"
PreparedStatement preparedStatement = conn.prepareStatement(sql);
for(int i=0; i<parameters.size(); i++){
preparedStatement.setString(i+1, parameters.get(i).toString());
}
this.rs = preparedStatement.executeQuery();
直到这里,没关系。获得ResultSet并对其进行处理之后,或者未获得仅用于preparedStatement.execute()
的resultSet都没有区别,我无法再次到达#someTable对象。
sql = "select count(*) from #someTable"
preparedStatement = conn.prepareStatement(sql);
this.rs = preparedStatement.executeQuery();
此处this.rs = preparedStatement.executeQuery();
部分给出了'Invalid object name #someTable'
。我仅使用一个Connection对象就可以完成上述所有操作,而无需关闭或重新打开它。我需要再次使用该临时表。有什么方法可以用Java中的PreparedStatement对象创建临时表并一次又一次地重用此临时表?问候
答案 0 :(得分:0)
您在第一条语句中创建的临时表在该请求的范围\生存期内存在。调用另一个查询后,您将进入另一个范围,因此不再存在,因为它将被清除。
解决方案要么是在同一调用中发出2个请求(不是很好),要么创建了一个可以被第二个查询访问的全局临时表(仍然不是很好)。
更好的解决方案是创建一个存储过程,该过程执行您所需的所有工作,并在过程中封装临时表,进行查询和整理。
PS我看不到任何周围的代码,但是在用这种代码构建查询时要小心SQL注入。
答案 1 :(得分:0)
参加聚会的时间很晚,但是面临相同的问题并发现上述答案有误:
阅读有关该问题的这篇文章:https://docs.microsoft.com/en-us/sql/connect/jdbc/using-usefmtonly?view=sql-server-2017
我发现使用PreparedStatement创建临时表是行不通的,但是如果我更改为使用Statement创建临时表,它将行得通(即使没有useFmtOnly)。 因此,首先从MS文章开始并以此为基础:
final String sql = "INSERT INTO #Bar VALUES (?)";
try (Connection c = DriverManager.getConnection(URL, USERNAME, PASSWORD)) {
try (Statement s = c.createStatement()) {
s.execute("CREATE TABLE #Bar(c1 int)");
}
try (PreparedStatement p1 = c.prepareStatement(sql); PreparedStatement p2 = c.prepareStatement(sql)) {
((SQLServerPreparedStatement) p1).setUseFmtOnly(true);
ParameterMetaData pmd1 = p1.getParameterMetaData();
System.out.println(pmd1.getParameterTypeName(1)); // prints int
ParameterMetaData pmd2 = p2.getParameterMetaData(); // throws exception, Invalid object name '#Bar'
}
}