Java 是否可以将GROUP BY与bind变量一起使用?

Java 是否可以将GROUP BY与bind变量一起使用?,java,sql,oracle,jdbc,prepared-statement,Java,Sql,Oracle,Jdbc,Prepared Statement,我想发出如下查询 select max(col1), f(:1, col2) from t group by f(:1, col2) 其中:1是绑定变量。使用PreparedStatement,如果我说 connection.prepareStatement ("select max(col1), f(?, col2) from t group by f(?, col2)") 我从DBMS得到一个错误,抱怨f(?,col2)不是一个GROUPBY表达式 在JDBC中通常如何解决这个问题?

我想发出如下查询

select max(col1), f(:1, col2) from t group by f(:1, col2)
其中
:1
是绑定变量。使用
PreparedStatement
,如果我说

connection.prepareStatement
  ("select max(col1), f(?, col2) from t group by f(?, col2)")
我从DBMS得到一个错误,抱怨
f(?,col2)
不是一个GROUPBY表达式


在JDBC中通常如何解决这个问题?

您是否尝试使用
而不是命名的绑定变量?还有,您使用的是哪种驱动程序?我使用瘦驱动程序尝试了这个简单的示例,它似乎工作得很好:

PreparedStatement ps = con.prepareStatement("SELECT COUNT(*), TO_CHAR(SYSDATE, ?) FROM DUAL GROUP BY TO_CHAR(SYSDATE, ?)");
ps.setString(1, "YYYY");
ps.setString(2, "YYYY");
ps.executeQuery();

在第二种情况下,实际上有两个变量-您需要使用相同的值发送它们。

我建议重新编写语句,以便只有一个bind参数。 这种方法有点难看,但会返回结果集:

select max(col1) 
     , f_col2
  from (
         select col1
              , f(? ,col2) as f_col2 
           from t
       )
 group
    by f_col2
这个重写的语句只引用了一个bind参数,所以现在DBMS看到GROUPBY子句和SELECT列表中的表达式是相同的

[编辑]

(我希望有一种更漂亮的方法,这就是为什么我更喜欢Oracle使用的命名绑定参数方法。使用Perl DBI驱动程序,位置参数在实际发送到Oracle的语句中转换为命名参数。)

一开始我没有看到问题,我不理解原来的问题。(显然,其他一些人也没有注意到。)但是在运行了一些测试用例之后,我明白了问题是什么,问题是什么

让我看看是否可以说明这个问题:如何让两个单独的(位置)绑定参数被(DBMS)视为对同一个(命名的)绑定参数的两个引用

DBMS希望GROUP BY中的表达式与SELECT列表中的表达式匹配。但是这两个表达式被认为是不同的,即使它们是相同的,唯一的区别是每个表达式引用不同的绑定变量。(我们可以演示一些至少某些DBMS允许的测试用例,但还有一些更一般的用例会引发异常。)

在这一点上,简短的回答是,这让我感到困惑。我的建议(可能不是对原始问题的实际答案)是重新构造查询

[/编辑]

如果这种方法不起作用,或者您在解决它时遇到其他问题,我可以提供更多细节。或者,如果性能有问题(我可以看到优化器为重新编写的查询选择了不同的计划,即使它返回指定的结果集。为了进一步测试,我们确实需要知道什么DBMS、什么驱动程序、统计数据等。)

编辑(八年半后)

再次尝试重写查询。同样,我提出的唯一解决方案是使用一个绑定占位符的查询。这一次,我们将它粘贴到一个内联视图中,该视图返回一行,并将其连接到t。我能看到它在做什么;我不确定Oracle优化器将如何看待这一点。我们可能希望(或需要)执行显式转换,例如,
到作为param的_NUMBER(?)
到作为param的_DATE(?,…),到作为param的
到作为param的_CHAR(?)的
,具体取决于bind参数的数据类型,以及我们希望从视图返回的数据类型。)

这就是我在MySQL中的做法。我的答案中的原始查询在内联视图(MySQL派生表)中执行联接操作。如果可以避免的话,我们希望避免实现Hughjas派生表。同样,只要
sql\u模式
不包括
仅包含
,MySQL可能会让原始查询滑动。MySQL还允许我们从DUAL中删除


根据MadusankaD的回答,在过去八年中,Oracle增加了对在JDBC驱动程序中重用相同命名绑定参数的支持,并保留了等效性。(我还没有测试过,但如果现在可以,那就太好了。)

即使您通过JDBC驱动程序(使用
PreparedStatement
)发出了如下查询:

select max(col1), f(:1, col2) from t group by f(:1, col2)
最后,JDBC驱动程序在解析到数据库之前替换了下面的查询,即使您在这两个位置使用了相同的绑定变量名

select max(col1), f(*:1*, col2) from t group by f(*:2*, col2)
但在oracle中,这不会被识别为有效的GROUPBY子句。 而且普通的JDBC驱动程序也不支持命名绑定变量

为此,您可以为您的连接使用
OraclePreparedStatement
类。这意味着它是oracle JDBC。然后可以使用命名绑定变量。它会解决你的问题

从Oracle Database 10g JDBC驱动程序开始,使用
setXXXAtName
方法支持按名称绑定


您到底想绑定什么?向我们展示您的所有代码,而不仅仅是一个片段。您可以绑定像“yyy”这样的值,但不能绑定列名。更新:现在我知道怎么回事了。DBMS无法识别GROUP BY中的表达式与SELECT列表中的表达式相同。它将这些视为两种不同的表达方式。使用命名绑定变量可以避免这个问题,因为只有一个值。@Cade:将两个变量设置为相同的值是不够的,DBMS会看到两个单独的绑定参数。DBMS在SELECT和GROUP BY中看到了不同的表达式。我担心可能是这种情况。我总是使用存储过程。这是一个进步(使用
setXXXAtName
方法设置单个命名的bind参数,并使同一个bind占位符引用同一语句中的多个位置,并且Oracle optimizer识别具有占位符的表达式是相同的,因此可以在GROUP BY子句和SELECT列表中使用相同的表达式。这是一个巨大的问题在普通JDBC上的功能验证。
select max(col1), f(*:1*, col2) from t group by f(*:2*, col2)