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课(子查询)实验的主要内容,如果未能解决你的问题,请参考以下文章