使用开发人员桌面和开发人员Web的Oracle数据库中没有GROUPBY的HAVING子句

我按照标准做法的理解是, HAVING 将与 GROUP BY 一起用于过滤条件,而 WHERE 应该用于一般的按行过滤条件。

然而,关于是否使用 HAVING 作为 WHERE 子句的超集,在线讨论的结论不一。也就是说,它是否可以在没有 GROUP BY 的情况下使用,在这种情况下它作为 WHERE 子句工作。

我想了解在 Oracle、Microsoft SQL 服务器、MySQL、PostGreSQL 和其他工具中使用 HAVING 子句的行业实践是什么。

我在执行此查询时观察到的一件有趣的事情:

SELECT *
FROM SH.SALES
WHERE amount_sold > 1000
HAVING amount_sold < 2000;

它在 Oracle SQL 开发人员桌面中执行时出错,而在 Oracle SQL 开发人员 Web 中成功运行。

回答

这是一个很好的问题和难题!

Oracle SQL Developer Web 是通过 Oracle REST 数据服务 (ORDS) 提供的。有一个 RESTful Web 服务用于执行“即席”SQL 语句和脚本。

我们不是在一次调用中从查询中返回所有行,而是对它们进行分页。而不是保持结果集打开和进程运行,我们坚持 RESTful 方式,并在单个调用和响应上完成所有工作。

我们如何做到这一点?

好吧,当您从问题中输入该查询并执行它时,在后端,这实际上并不是执行的内容。

我们用另一个 SELECT 包装该查询,并使用 ROW_NUMBER() OVER 分析函数调用。这允许我们“窗口化”查询结果,在这种情况下,在第 1 行和第 26 行之间,或该查询的前 25 行,即您的查询。

SELECT *
  FROM (
       SELECT Q_.*,
              ROW_NUMBER() OVER(
                      ORDER BY 1
              ) RN___
         FROM (
              select * 
from sh.sales
where amount_sold > 1000
having amount_sold < 2000
       ) Q_
)
 WHERE RN___ BETWEEN :1 AND :2

好吧,那又怎样?

好吧,优化器发现这个查询仍然可以运行,即使 have 子句不合适。

在搜索最佳执行计划之前,优化器始终可以自由地重新排列查询。

在这种情况下,10053 跟踪显示来自 SQL Dev Web 的如下查询(我使用的是 EMP,但同样适用于任何表)

SELECT *
  FROM (
       SELECT Q_.*,
              ROW_NUMBER() OVER(
                      ORDER BY 1
              ) RN___
         FROM (
              SELECT *
              FROM emp
              WHERE sal > 1000
HAVING sal < 2000
       ) Q_
)
 WHERE RN___ BETWEEN :1 AND :2

在针对计划进行优化之前,已在内部转换为以下内容。

SELECT 
  subq.EMPNO EMPNO,
  subq.ENAME ENAME,
  subq.JOB JOB,
  subq.MGR MGR,
  subq.HIREDATE HIREDATE,
  subq.SAL SAL,subq.COMM COMM,
  subq.DEPTNO DEPTNO,
  subq.RN___ RN___ 
FROM  
  (SELECT 
      EMP.EMPNO EMPNO,
      EMP.ENAME ENAME,
      EMP.JOB JOB,EMP.MGR MGR,
      EMP.HIREDATE HIREDATE,
      EMP.SAL SAL,
      EMP.COMM COMM,
      EMP.DEPTNO DEPTNO,
      ROW_NUMBER() OVER ( ORDER BY  NULL ) RN___ 
   FROM EMP EMP 
   WHERE EMP.SAL>1000 AND TO_NUMBER(:B1)>=TO_NUMBER(:B2)
   ) subq 
WHERE subq.RN___>=TO_NUMBER(:B3) 
AND subq.RN___<=TO_NUMBER(:B4)

请注意 HAVING 已从查询中转换/优化,这让它进入执行阶段。

主要感谢 AskTom 的@connor-mcdonald帮助我解决这个问题。

这就是为什么它可以在 SQL Developer Web 中运行,但不能在 SQL Developer Desktop 中运行,在 SQL Developer Desktop 中,查询完全按照编写的方式执行。

  • I've updated my answer with a major assist from Connor McDonald of Oracle AskTom

以上是使用开发人员桌面和开发人员Web的Oracle数据库中没有GROUPBY的HAVING子句的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>