在 Oracle 中使用和不使用 KEEP 进行分区

新手上路,请多包涵

我遇到了两个似乎具有相同结果的查询:在分区上应用聚合函数。

我想知道这两个查询之间是否有任何区别:

 SELECT empno,
   deptno,
   sal,
   MIN(sal) OVER (PARTITION BY deptno) "Lowest",
   MAX(sal) OVER (PARTITION BY deptno) "Highest"
FROM empl

SELECT empno,
   deptno,
   sal,
   MIN(sal) KEEP (DENSE_RANK FIRST ORDER BY sal) OVER (PARTITION BY deptno) "Lowest",
   MAX(sal) KEEP (DENSE_RANK LAST ORDER BY sal) OVER (PARTITION BY deptno) "Highest"
FROM empl

第一个版本更合乎逻辑,但第二个版本可能是某种特殊情况,也许是一些性能优化。

原文由 aurelije 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 494
2 个回答

在您的示例中,没有区别,因为您的聚合位于您正在排序的同一列上。 “KEEP”的真正意义/力量在于您在 不同的 列上进行聚合和排序。例如(从另一个答案中借用“测试”表)……

 SELECT deptno,  min(name) keep ( dense_rank first order by sal desc, name  ) ,
max(sal)
FROM test
group by deptno

;

此查询获取每个部门中薪水最高的人的姓名。考虑没有“KEEP”子句的替代方案:

 SELECT deptno, name, sal
FROM test t
WHERE not exists ( SELECT 'person with higher salary in same department'
                                            FROM test t2
                                            WHERE t2.deptno = t.deptno
                                            and ((  t2.sal > t.sal )
                                            OR ( t2.sal = t.sal AND t2.name < t.name ) ) )

KEEP 子句更简单、更高效(在这个简单的示例中,只有 3 个一致的获取与 34 个获取替代)。

原文由 Matthew McPeak 发布,翻译遵循 CC BY-SA 3.0 许可协议

详细说明@MT0 的答案中提到的一个区别:在您的第一个查询中,聚合函数 MIN 和 MAX 正在完成这项工作,而在第二个查询中,实际行由 FIRST、LAST 和 KEEP 选择。

您甚至可以在第二个示例中将 MAX 替换为 MIN,它仍然会给出正确的答案(最高薪水)。

有关详细信息,请参阅以下 文章

原文由 Roger Smith 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进