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

Posted dingdingfish

tags:

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

概述

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

创建环境

首先创建表:

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

create table colours (
  colour_name           varchar2(10),
  minimum_bricks_needed integer
);

insert into colours values ( 'blue', 2 );
insert into colours values ( 'green', 3 );
insert into colours values ( 'red', 2 );
insert into colours values ( 'orange', 1);
insert into colours values ( 'yellow', 1 );
insert into colours values ( 'purple', 1 );

insert into bricks values ( 1, 'blue' );
insert into bricks values ( 2, 'blue' );
insert into bricks values ( 3, 'blue' );
insert into bricks values ( 4, 'green' );
insert into bricks values ( 5, 'green' );
insert into bricks values ( 6, 'red' );
insert into bricks values ( 7, 'red' );
insert into bricks values ( 8, 'red' );
insert into bricks values ( 9, null );

commit;

查看数据:

SQL> select * from bricks;

   BRICK_ID    COLOUR
___________ _________
          1 blue
          2 blue
          3 blue
          4 green
          5 green
          6 red
          7 red
          8 red
          9

9 rows selected.

SQL> select * from colours;

   COLOUR_NAME    MINIMUM_BRICKS_NEEDED
______________ ________________________
blue                                  2
green                                 3
red                                   2
orange                                1
yellow                                1
purple                                1

6 rows selected.

内联视图(Inline Views)

select * from (
  select * from bricks /* 此行为内联视图 */
)

-- 内联视图加表别名
select * from (
  select colour, count(*) c
  from   bricks
  group  by colour
) brick_counts
join   colours
on     brick_counts.colour = colours.colour_name
and    brick_counts.c < colours.minimum_bricks_needed;

   COLOUR    C    COLOUR_NAME    MINIMUM_BRICKS_NEEDED
_________ ____ ______________ ________________________
green        2 green                                 3

嵌套子查询(Nested Subqueries)

位于where子句。

SQL> select * from colours c
  2  where  c.colour_name in (
  3    select b.colour from bricks b
  4  );

   COLOUR_NAME    MINIMUM_BRICKS_NEEDED
______________ ________________________
blue                                  2
green                                 3
red                                   2

-- 使用exists的等价实现。其中的null也可以换为1,使用null的好处也许是可以减少返回的数据。
SQL> select * from colours c
  2  where  exists (
  3    select null from bricks b
  4    where  b.colour = c.colour_name
  5  );

   COLOUR_NAME    MINIMUM_BRICKS_NEEDED
______________ ________________________
blue                                  2
green                                 3
red                                   2

-- 子查询中也可以加过滤
SQL> select * from colours c
  2  where  c.colour_name in (
  3    select b.colour from bricks b
  4    where  b.brick_id < 5
  5  );

   COLOUR_NAME    MINIMUM_BRICKS_NEEDED
______________ ________________________
blue                                  2
green                                 3

-- 使用exists的等价实现
SQL> select * from colours c
  2  where  exists (
  3    select null from bricks b
  4    where  b.colour = c.colour_name
  5    and    b.brick_id < 5
  6  );

   COLOUR_NAME    MINIMUM_BRICKS_NEEDED
______________ ________________________
blue                                  2
green                                 3

相关与不相关(Correlated vs. Uncorrelated)

如果子查询与父查询有Join关系,则称为相关,否则为不相关。可以认为是IN和EXISTS的区别。

不相关子查询示例:

select * from colours
where  exists (
  select null from bricks
);

相关子查询示例:

select * from colours c
where  c.colour_name in (
  select b.colour from bricks b
  where  b.brick_id < 5
);

IN和EXISTS之前都可以加NOT,此不赘述。

标量子查询(Scalar Subqueries)

标量子查询只返回一个值(一行一列),因此可以在列的位置上以其替代。例如以下,注意有无group by的区别:

SQL> select colour_name, (
  2           select count(*)
  3           from   bricks b
  4           where  b.colour = c.colour_name
  5           group  by b.colour
  6         ) brick_counts
  7  from   colours c;

   COLOUR_NAME    BRICK_COUNTS
______________ _______________
blue                         3
green                        2
red                          3
orange
yellow
purple

6 rows selected.

SQL> select colour_name, (
  2           select count(*)
  3           from   bricks b
  4           where  b.colour = c.colour_name
  5           --group  by b.colour
  6         ) brick_counts
  7  from   colours c;

   COLOUR_NAME    BRICK_COUNTS
______________ _______________
blue                         3
green                        2
red                          3
orange                       0
yellow                       0
purple                       0

6 rows selected.

关联是必要的,否则返回多个值,就不是标量了。

SQL> select c.colour_name, (
  2           select count(*)
  3           from   bricks b
  4           group  by colour
  5         ) brick_counts
  6  from   colours c;

Error starting at line : 1 in command -
select c.colour_name, (
         select count(*)
         from   bricks b
         group  by colour
       ) brick_counts
from   colours c
Error report -
ORA-01427: single-row subquery returns more than one row

标量子查询也可以用在having子句中:

SQL> select colour, count(*) c
  2  from   bricks b
  3  group  by colour
  4  having count(*) < (
  5    select c.minimum_bricks_needed
  6    from   colours c
  7    where  c.colour_name = b.colour
  8  );

   COLOUR    C
_________ ____
green        2

常用表表达式(Common Table Expressions)

就是为子查询起别名。通过with子句实现。例如:

with brick_colour_counts as (
  select colour, count(*) 
  from   bricks
  group  by colour
) 
  select * from brick_colour_counts ;

之所以叫常用表,是因为此表达式(别名)可以反复使用。

Literate SQL

是指用Literate programming的理念编写SQL。也就是让SQL符合自然语言的习惯。子查询显然不符合,因此推荐用with子句。

with brick_counts as ( 
  -- 1. Count the bricks by colour
  select b.colour, count(*) c
  from   bricks b
  group  by b.colour
), average_bricks_per_colour as ( 
  -- 2. Take the average of these counts
  select avg ( c ) average_count
  from   brick_counts
)
  select * from brick_counts bc  
  join   average_bricks_per_colour ac
  -- 3. Return those rows where the value in step 1 is less than in step 2
  on     bc.c < average_count; 

这样会使你的SQL更易读,也更好维护(调试)。

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

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

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

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

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

Oracle开发者中级第9课(读取一致性)实验

Oracle开发者中级第9课(读取一致性)实验