一尘不染

是否可以将GROUP BY与绑定变量一起使用?

sql

我想发出如下查询

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)不是GROUP BY表达式。

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


阅读 191

收藏
2021-05-16

共1个答案

一尘不染

我建议重新编写该语句,以便只有一个绑定参数。这种方法有点丑陋,但是会返回结果集:

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 paramTO_DATE(?,'...') AS paramTO_CHAR(?) AS param,根据绑定参数的数据类型,我们要返回从视图中的数据类型。)

这就是我在MySQL中要做的事情。我的答案中的原始查询在内联视图(MySQL 派生表
)内执行联接操作。如果可以避免的话,我们希望避免实例化hughjass派生表。再说一次,只要sql_mode不包含,MySQL可能会让原始查询滑动ONLY_FULL_GROUP_BY。MySQL还可以让我们删除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驱动程序中重用相同的命名绑定参数并保持等效性的支持。(我尚未对此进行测试,但是如果现在可以正常运行,那就太好了。)

2021-05-16