我想发出如下查询
select max(col1), f(:1, col2) from t group by f(:1, col2)
:1绑定变量在哪里。使用PreparedStatement,如果我说
:1
PreparedStatement
connection.prepareStatement ("select max(col1), f(?, col2) from t group by f(?, col2)")
我从DBMS收到一个错误,抱怨它f(?, col2)不是GROUP BY表达式。
f(?, col2)
通常如何在JDBC中解决这个问题?
我建议重新编写该语句,以便只有一个绑定参数。这种方法有点丑陋,但是会返回结果集:
select max(col1) , f_col2 from ( select col1 , f(? ,col2) as f_col2 from t ) group by f_col2
该重写语句仅引用了一个绑定参数,因此,DBMS现在看到GROUP BY子句中的表达式与SELECT列表相同。
高温超导
[编辑]
(我希望有一个更漂亮的方法,这就是为什么我更喜欢Oracle使用的命名绑定参数方法。使用Perl DBI驱动程序,位置参数在实际发送给Oracle的语句中转换为命名参数。)
起初我没有看到问题,也没有理解最初的问题。(显然,其他几个人也错过了它。)但是在运行了一些测试用例之后,我突然意识到问题出在哪里,问题出在什么地方。
让我看看是否可以说明这个问题:如何获得两个单独的(位置)绑定参数(由DBMS来对待),就好像是对同一个(命名)绑定参数的两个引用一样。
DBMS期望GROUP BY中的表达式与SELECT列表中的表达式匹配。但是,即使两个表达式都相同,但唯一的区别是每个表达式都引用了一个不同的绑定变量,这两个表达式仍被认为是不同的。(我们可以演示至少一些DBMS允许的一些测试用例,但是还有一些更常见的情况会引发异常。)
在这一点上,简短的答案是,这让我感到困惑。我的建议(可能不是对原始问题的实际答案)是重组查询。
[/编辑]
如果这种方法行不通,或者您在解决该问题时遇到其他问题,我可以提供更多详细信息。或者,如果性能存在问题(我可以看到优化器为重写的查询选择了不同的计划,即使它返回了指定的结果集。对于进一步的测试,我们真的需要知道什么DBMS,什么驱动程序,统计信息等)
编辑 (八年半后)
再次尝试查询重写。同样,我想出的唯一解决方案是带有一个绑定占位符的查询。这次,我们将其粘贴到一个内联视图中,该视图返回单行,并将其连接到t。我可以看到它在做什么;我不确定Oracle优化器如何看待这一点。我们可能希望(或需要)做一个明确的转换例如TO_NUMBER(?) AS param,TO_DATE(?,'...') AS param,TO_CHAR(?) AS param,根据绑定参数的数据类型,我们要返回从视图中的数据类型。)
TO_NUMBER(?) AS param
TO_DATE(?,'...') AS param
TO_CHAR(?) AS param
这就是我在MySQL中要做的事情。我的答案中的原始查询在内联视图(MySQL 派生表 )内执行联接操作。如果可以避免的话,我们希望避免实例化hughjass派生表。再说一次,只要sql_mode不包含,MySQL可能会让原始查询滑动ONLY_FULL_GROUP_BY。MySQL还可以让我们删除FROM DUAL)
sql_mode
ONLY_FULL_GROUP_BY
FROM DUAL
SELECT MAX(t.col1) , f( v.param ,t.col2) FROM t CROSS JOIN ( SELECT ? AS param FROM DUAL) v GROUP BY f( v.param ,t.col2)
根据MadusankaD的回答,在过去的八年中,Oracle增加了对在JDBC驱动程序中重用相同的命名绑定参数并保持等效性的支持。(我尚未对此进行测试,但是如果现在可以正常运行,那就太好了。)