Kar*_*ikS 6 oracle having oracle-sqldeveloper having-clause oracle-ords
我按照标准做法的理解是, 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;
Run Code Online (Sandbox Code Playgroud)
它在 Oracle SQL 开发人员桌面中执行时出错,而在 Oracle SQL 开发人员 Web 中成功运行。
tha*_*ith 10
这是一个很好的问题和难题!
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
Run Code Online (Sandbox Code Playgroud)
好吧,那又怎样?
好吧,优化器发现这个查询仍然可以运行,即使 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
Run Code Online (Sandbox Code Playgroud)
在针对计划进行优化之前,已在内部转换为以下内容。
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)
Run Code Online (Sandbox Code Playgroud)
请注意 HAVING 已从查询中转换/优化,这让它进入执行阶段。
主要感谢 AskTom 的@connor-mcdonald帮助我解决这个问题。
这就是为什么它可以在 SQL Developer Web 中运行,但不能在 SQL Developer Desktop 中运行,在 SQL Developer Desktop 中,查询完全按照编写的方式执行。