Oracle开发者中级第4课(分析函数)实验

Posted dingdingfish

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle开发者中级第4课(分析函数)实验相关的知识,希望对你有一定的参考价值。

概述

本实验参考DevGym中的实验指南

创建环境

首先创建表:

create table bricks (
  brick_id integer,
  colour   varchar2(10),
  shape    varchar2(10),
  weight   integer
);

insert into bricks values ( 1, 'blue', 'cube', 1 );
insert into bricks values ( 2, 'blue', 'pyramid', 2 );
insert into bricks values ( 3, 'red', 'cube', 1 );
insert into bricks values ( 4, 'red', 'cube', 2 );
insert into bricks values ( 5, 'red', 'pyramid', 3 );
insert into bricks values ( 6, 'green', 'pyramid', 1 );

commit;

查看数据:

SQL> select * from bricks;

   BRICK_ID    COLOUR      SHAPE    WEIGHT
___________ _________ __________ _________
          1 blue      cube               1
          2 blue      pyramid            2
          3 red       cube               1
          4 red       cube               2
          5 red       pyramid            3
          6 green     pyramid            1

6 rows selected.

聚合和分析函数的区别

第一个是聚合(多行到1行),后续两个是分析函数(使用了over,仍保留多行)。

SQL> select count(*) from bricks;

   COUNT(*)
___________
          6

SQL> select count(*) over () from bricks;

   COUNT(*)OVER()
_________________
                6
                6
                6
                6
                6
                6

6 rows selected.

SQL> select b.*,
  2         count(*) over () total_count
  3  from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    TOTAL_COUNT
___________ _________ __________ _________ ______________
          1 blue      cube               1              6
          2 blue      pyramid            2              6
          3 red       cube               1              6
          4 red       cube               2              6
          5 red       pyramid            3              6
          6 green     pyramid            1              6

6 rows selected.

Partition By

以下SQL展示了Group By和Partition By的区别。实际上也就是聚合与分析函数的区别。

SQL> select colour, count(*), sum ( weight )
  2  from   bricks
  3  group  by colour;

   COLOUR    COUNT(*)    SUM(WEIGHT)
_________ ___________ ______________
red                 3              6
green               1              1
blue                2              3

SQL> select b.*,
  2         count(*) over (
  3           partition by colour
  4         ) bricks_per_colour,
  5         sum ( weight ) over (
  6           partition by colour
  7         ) weight_per_colour
  8  from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    BRICKS_PER_COLOUR    WEIGHT_PER_COLOUR
___________ _________ __________ _________ ____________________ ____________________
          2 blue      pyramid            2                    2                    3
          1 blue      cube               1                    2                    3
          6 green     pyramid            1                    1                    1
          5 red       pyramid            3                    3                    6
          4 red       cube               2                    3                    6
          3 red       cube               1                    3                    6

6 rows selected.

练习的答案如下:

select b.*, 
       count(*) over (
         partition by shape
       ) bricks_per_shape, 
       median ( weight ) over (
         partition by shape
       ) median_weight_per_shape
from   bricks b
order  by shape, weight, brick_id;

Order By

over加order by可实现实时合计(running totals),例如:

SQL> select b.*,
  2         count(*) over (
  3           order by brick_id
  4         ) running_total,
  5         sum ( weight ) over (
  6           order by brick_id
  7         ) running_weight
  8  from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    RUNNING_TOTAL    RUNNING_WEIGHT
___________ _________ __________ _________ ________________ _________________
          1 blue      cube               1                1                 1
          2 blue      pyramid            2                2                 3
          3 red       cube               1                3                 4
          4 red       cube               2                4                 6
          5 red       pyramid            3                5                 9
          6 green     pyramid            1                6                10

6 rows selected.

Partition By + Order By

两者结合可实现partition内的实时合计(running totals):

SQL>
select b.*, 
       count(*) over (
         partition by colour
         order by brick_id
       ) running_total, 
       sum ( weight ) over (
         partition by colour
         order by brick_id
       ) running_weight
from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    RUNNING_TOTAL    RUNNING_WEIGHT
___________ _________ __________ _________ ________________ _________________
          1 blue      cube               1                1                 1
          2 blue      pyramid            2                2                 3
          6 green     pyramid            1                1                 1
          3 red       cube               1                1                 1
          4 red       cube               2                2                 3
          5 red       pyramid            3                3                 6

6 rows selected.

Windowing子句

当over + order by结合时,数据库添加了以下默认的Windowing子句,即包括值小于或等于当前行的所有行。:

range between unbounded preceding and current row

所以在下例中,weight相同的行,RUNNING_TOTAL和RUNNING_WEIGHT也是相同的:

SQL> select b.*,
  2         count(*) over (
  3           order by weight
  4         ) running_total,
  5         sum ( weight ) over (
  6           order by weight
  7         ) running_weight
  8  from   bricks b
  9  order  by weight;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    RUNNING_TOTAL    RUNNING_WEIGHT
___________ _________ __________ _________ ________________ _________________
          1 blue      cube               1                3                 3
          3 red       cube               1                3                 3
          6 green     pyramid            1                3                 3
          4 red       cube               2                5                 7
          2 blue      pyramid            2                5                 7
          5 red       pyramid            3                6                10

6 rows selected.

窗口是可以调整的,以下SQL将默认的range替换为rows:

SQL> select b.*,
  2         count(*) over (
  3           order by weight
  4           rows between unbounded preceding and current row
  5         ) running_total,
  6         sum ( weight ) over (
  7           order by weight
  8           rows between unbounded preceding and current row
  9         ) running_weight
 10  from   bricks b
 11  order  by weight;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    RUNNING_TOTAL    RUNNING_WEIGHT
___________ _________ __________ _________ ________________ _________________
          1 blue      cube               1                1                 1
          3 red       cube               1                2                 2
          6 green     pyramid            1                3                 3
          4 red       cube               2                4                 5
          2 blue      pyramid            2                5                 7
          5 red       pyramid            3                6                10

6 rows selected.

由于weight有相同的,为避免出现tie的现象,还需要多添加一个order by brick_id,使结果集顺序固定,或者也可以说,使结果集唯一:

select b.*, 
       count(*) over (
         order by weight, brick_id
         rows between unbounded preceding and current row
       ) running_total, 
       sum ( weight ) over (
         order by weight, brick_id
         rows between unbounded preceding and current row
       ) running_weight
from   bricks b
order  by weight, brick_id;

滑动窗口(Sliding Windows)

看3个例子:

SQL> select b.*,
  2         sum ( weight ) over (
  3           order by weight
  4           rows between 1 preceding and current row
  5         ) running_row_weight,
  6         sum ( weight ) over (
  7           order by weight
  8           range between 1 preceding and current row
  9         ) running_value_weight
 10  from   bricks b
 11  order  by weight, brick_id;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    RUNNING_ROW_WEIGHT    RUNNING_VALUE_WEIGHT
___________ _________ __________ _________ _____________________ _______________________
          1 blue      cube               1                     1                       3
          3 red       cube               1                     2                       3
          6 green     pyramid            1                     2                       3
          2 blue      pyramid            2                     3                       7
          4 red       cube               2                     4                       7
          5 red       pyramid            3                     5                       7

6 rows selected.

SQL> select b.*,
  2         sum ( weight ) over (
  3           order by weight
  4           rows between 1 preceding and 1 following
  5         ) sliding_row_window,
  6         sum ( weight ) over (
  7           order by weight
  8           range between 1 preceding and 1 following
  9         ) sliding_value_window
 10  from   bricks b
 11  order  by weight;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    SLIDING_ROW_WINDOW    SLIDING_VALUE_WINDOW
___________ _________ __________ _________ _____________________ _______________________
          1 blue      cube               1                     2                       7
          3 red       cube               1                     3                       7
          6 green     pyramid            1                     4                       7
          4 red       cube               2                     5                      10
          2 blue      pyramid            2                     7                      10
          5 red       pyramid            3                     5                       7

6 rows selected.

SQL> select b.*,
  2         count (*) over (
  3           order by weight
  4           range between 2 preceding and 1 preceding
  5         ) count_weight_2_lower_than_current,
  6         count (*) over (
  7           order by weight
  8           range between 1 following and 2 following
  9         ) count_weight_2_greater_than_current
 10  from   bricks b
 11  order  by weight;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    COUNT_WEIGHT_2_LOWER_THAN_CURRENT    COUNT_WEIGHT_2_GREATER_THAN_CURRENT
___________ _________ __________ _________ ____________________________________ ______________________________________
          1 blue      cube               1                                    0                                      3
          3 red       cube               1                                    0                                      3
          6 green     pyramid            1                                    0                                      3
          4 red       cube               2                                    3                                      1
          2 blue      pyramid            2                                    3                                      1
          5 red       pyramid            3                                    5                                      0

6 rows selected.

分析函数的过滤

结合函数的过滤用having:

SQL> select colour from bricks
  2  group  by colour
  3  having count(*) >= 2;

   COLOUR
_________
red
blue

由于数据库处理where条件在前,分析函数在后。因此分析函数的过滤仍需结合子查询:

SQL> select b.*,
  2           count(*) over ( partition by colour ) colour_count
  3    from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    COLOUR_COUNT
___________ _________ __________ _________ _______________
          2 blue      pyramid            2               2
          1 blue      cube               1               2
          6 green     pyramid            1               1
          5 red       pyramid            3               3
          4 red       cube               2               3
          3 red       cube               1               3

6 rows selected.

SQL> select * from (
  2    select b.*,
  3           count(*) over ( partition by colour ) colour_count
  4    from   bricks b
  5  )
  6  where  colour_count >= 2;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    COLOUR_COUNT
___________ _________ __________ _________ _______________
          2 blue      pyramid            2               2
          1 blue      cube               1               2
          5 red       pyramid            3               3
          4 red       cube               2               3
          3 red       cube               1               3

更多分析函数

包括row_number,rank,dense_rank,lag,lead,first_value,last_value

-- row_number,rank,dense_rank示例
SQL> select brick_id, weight,
  2         row_number() over ( order by weight ) rn,
  3         rank() over ( order by weight ) rk,
  4         dense_rank() over ( order by weight ) dr
  5  from   bricks;

   BRICK_ID    WEIGHT    RN    RK    DR
___________ _________ _____ _____ _____
          1         1     1     1     1
          3         1     2     1     1
          6         1     3     1     1
          4         2     4     4     2
          2         2     5     4     2
          5         3     6     6     3

6 rows selected.

-- lag,lead示例,即前一个值和后一个值
SQL> select b.*,
  2         lag ( shape ) over ( order by brick_id ) prev_shape,
  3         lead ( shape ) over ( order by brick_id ) next_shape
  4  from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    PREV_SHAPE    NEXT_SHAPE
___________ _________ __________ _________ _____________ _____________
          1 blue      cube               1               pyramid
          2 blue      pyramid            2 cube          cube
          3 red       cube               1 pyramid       cube
          4 red       cube               2 cube          pyramid
          5 red       pyramid            3 cube          pyramid
          6 green     pyramid            1 pyramid

6 rows selected.

-- first_value,last_value示例。排序集合中的第一个和最后一个值。注意以下2个示例的区别,和窗口有关。
SQL> select b.*,
  2         first_value ( weight ) over (
  3           order by brick_id
  4         ) first_weight_by_id,
  5         last_value ( weight ) over (
  6           order by brick_id
  7         ) last_weight_by_id
  8  from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    FIRST_WEIGHT_BY_ID    LAST_WEIGHT_BY_ID
___________ _________ __________ _________ _____________________ ____________________
          1 blue      cube               1                     1                    1
          2 blue      pyramid            2                     1                    2
          3 red       cube               1                     1                    1
          4 red       cube               2                     1                    2
          5 red       pyramid            3                     1                    3
          6 green     pyramid            1                     1                    1

6 rows selected.

SQL> select b.*,
  2         first_value ( weight ) over (
  3           order by brick_id
  4         ) first_weight_by_id,
  5         last_value ( weight ) over (
  6           order by brick_id
  7           range between current row and unbounded following
  8         ) last_weight_by_id
  9  from   bricks b;

   BRICK_ID    COLOUR      SHAPE    WEIGHT    FIRST_WEIGHT_BY_ID    LAST_WEIGHT_BY_ID
___________ _________ __________ _________ _____________________ ____________________
          1 blue      cube               1                     1                    1
          2 blue      pyramid            2                     1                    1
          3 red       cube               1                     1                    1
          4 red       cube               2                     1                    1
          5 red       pyramid            3                     1                    1
          6 green     pyramid            1                     1                    1

6 rows selected.

以上是关于Oracle开发者中级第4课(分析函数)实验的主要内容,如果未能解决你的问题,请参考以下文章

Oracle开发者中级第8课(Merge)实验

Oracle开发者中级第8课(Merge)实验

Oracle开发者中级第2课(子查询)实验

Oracle开发者中级第1课(Null)实验

Oracle开发者中级第7课(层级查询)实验

Oracle开发者中级第7课(层级查询)实验