9

我用 Oracle 编写了一个复杂的 SQL 查询,我想在同一个分区上使用两个分析函数。

让我们很简单,但不要太多:

SELECT col1,
       MAX(col2) OVER(PARTITION BY col3, col4, col5, col6,
                                   CASE WHEN col7 LIKE 'foo'
                                        THEN SUBSTR(col7,1,5)
                                        ELSE col7
                                   END
                                   ORDER BY col5 ASC, col6 DESC),
       MIN(col2) OVER(PARTITION BY col3, col4, col5, col6,
                                   CASE WHEN col7 LIKE 'foo'
                                        THEN SUBSTR(col7,1,5)
                                        ELSE col7
                                   END
                                   ORDER BY col5 ASC, col6 DESC)
  FROM my_table;

是否有更优雅的语法来分解PARTITION BY子句?

谢谢你。

4

3 回答 3

13

如果您指的是这样的标准 WINDOW 子句:

SELECT col1,
       MAX(col2) OVER(w),
       MIN(col2) OVER(w)
FROM my_table
WINDOW w AS (PARTITION BY col3, col4, col5, col6,
                               CASE WHEN col7 LIKE 'foo'
                                    THEN SUBSTR(col7,1,5)
                                    ELSE col7
                               END
                               ORDER BY col5 ASC, col6 DESC);

那么我相信答案是否定的,Oracle 不支持这个(用 11gR2 检查)。

于 2011-03-29T13:23:31.793 回答
5

您可以使用子查询分解,也称为 with 子句:

(未经测试)

with t as
( select col1
       , col2
       , col3
       , col4
       , col5
       , col6
       , case col7
         when 'foo' then
           substr(col7,1,5)
         else
           col7
         end col7
    from my_table
)
select col1
     , max(col2) over (partition by col3,col4,col5,col6,col7 order by col5,col6 desc) 
     , min(col2) over (partition by col3,col4,col5,col6,col7 order by col5,col6 desc) 
  from t

问候,
罗布。

于 2011-03-29T13:20:50.777 回答
0

分区定义可以与WINDOW子句一起使用。从版本 20c 开始,Oracle 支持它:

增强的分析功能

SELECT 语句的 query_block 子句现在支持 window_clause,它实现了 SQL:2011 标准中定义的 SQL 标准表表达式的 window 子句。

选择

在此处输入图像描述

  • 请注意,OVER window_name不等同于OVER (window_name ...)OVER (window_name ...)意味着复制和修改窗口规范,如果引用的窗口规范包含 windowing_clause,则将被拒绝。

  • 您不能将 existing_window_name 与 windowing_clause 一起使用


查询可以重写为:

SELECT col1,
       MAX(col2) OVER w AS max_col2,
       MIN(col2) OVER w AS min_col2
FROM my_table
WINDOW w AS (PARTITION BY col3, col4, col5, col6,
                          CASE WHEN col7 LIKE 'foo'
                               THEN SUBSTR(col7,1,5)
                               ELSE col7
                          END
                          ORDER BY col5 ASC, col6 DESC);

请注意,可以扩展窗口定义的一部分,例如查询可以共享PARTITION BY但具有不同的排序:

SELECT col_x, 
       FIRST_VALUE(col_y) OVER (w ORDER BY col3), 
       FIRST_VALUE(col_z) OVER (w ORDER BY col4)
FROM tab
WINDOW w AS (PARTITION BY col1, col2);

我们不能执行类似共享相同PARTITION BYORDER BY具有不同窗口大小的操作:

SELECT col_x, 
       AVG(col_y) OVER (w ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) AS moving_avg_3, 
       AVG(col_y) OVER (w ROWS BETWEEN 5 PRECEDING AND CURRENT ROW) AS moving_avg_5
FROM tab
WINDOW w AS (PARTITION BY col1, col2 ORDER BY col3)
于 2020-02-16T10:15:30.797 回答