Oracle开发者中级第5课(Pivot 和Unpivot)实验
Posted dingdingfish
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Oracle开发者中级第5课(Pivot 和Unpivot)实验相关的知识,希望对你有一定的参考价值。
概述
本实验参考DevGym中的实验指南。
创建环境
就1个表:
create table match_results (
match_date date,
location varchar2(20),
home_team_name varchar2(20),
away_team_name varchar2(20),
home_team_points integer,
away_team_points integer
);
insert into match_results values ( date'2018-01-01', 'Snowley', 'Underrated United', 'Terrible Town', 2, 0 );
insert into match_results values ( date'2018-01-01', 'Coldgate', 'Average Athletic', 'Champions City', 1, 4 );
insert into match_results values ( date'2018-02-01', 'Dorwall', 'Terrible Town', 'Average Athletic', 0, 1 );
insert into match_results values ( date'2018-03-01', 'Coldgate', 'Average Athletic', 'Underrated United', 3, 3 );
insert into match_results values ( date'2018-03-02', 'Newdell', 'Champions City', 'Terrible Town', 8, 0 );
commit;
查看数据,学到两个单词,home team和away team表示主队和客队:
SQL> select * from match_results;
MATCH_DATE LOCATION HOME_TEAM_NAME AWAY_TEAM_NAME HOME_TEAM_POINTS AWAY_TEAM_POINTS
_____________ ___________ ____________________ ____________________ ___________________ ___________________
01-JAN-18 Snowley Underrated United Terrible Town 2 0
01-JAN-18 Coldgate Average Athletic Champions City 1 4
01-FEB-18 Dorwall Terrible Town Average Athletic 0 1
01-MAR-18 Coldgate Average Athletic Underrated United 3 3
02-MAR-18 Newdell Champions City Terrible Town 8 0
Manual Pivot
每个地点的比赛次数如下,但是我们需要其旋转90度的结果:
select location, count (*)
from match_results
group by location;
LOCATION COUNT(*)
___________ ___________
Newdell 1
Snowley 1
Coldgate 2
Dorwall 1
如果不用pivot子句,只能用以下SQL实现,笨拙易错:
select count ( case when location = 'Snowley' then 1 end ) snowley,
count ( case when location = 'Coldgate' then 1 end ) coldgate,
count ( case when location = 'Dorwall' then 1 end ) dorwall,
count ( case when location = 'Newdell' then 1 end ) newdell
from match_results;
SNOWLEY COLDGATE DORWALL NEWDELL
__________ ___________ __________ __________
1 2 1 1
Pivot Clause
with rws as (
select location from match_results
)
select * from rws
pivot (
count(*) for location in (
'Snowley', 'Coldgate', 'Dorwall', 'Newdell'
)
);
'Snowley' 'Coldgate' 'Dorwall' 'Newdell'
____________ _____________ ____________ ____________
1 2 1 1
with rws as (
select location from match_results
)
select * from rws
pivot (
count(*) for location in (
'Snowley', 'Coldgate', 'Dorwall'
)
);
'Snowley' 'Coldgate' 'Dorwall'
____________ _____________ ____________
1 2 1
例题1答案:
with rws as (
select location, match_date from match_results
)
select * from rws
pivot (
max(match_date)
for location in (
'Snowley', 'Coldgate', 'Dorwall', 'Newdell'
)
);
'Snowley' 'Coldgate' 'Dorwall' 'Newdell'
____________ _____________ ____________ ____________
01-JAN-18 01-MAR-18 01-FEB-18 02-MAR-18
例题2答案:
with rws as (
select home_team_name from match_results
)
select * from rws
pivot (
count (*)
for home_team_name
in (
'Underrated United', 'Average Athletic', 'Terrible Town', 'Champions City'
)
);
'Underrated United' 'Average Athletic' 'Terrible Town' 'Champions City'
______________________ _____________________ __________________ ___________________
1 2 1 1
Implicit Group By
输入表中不在数据透视子句中的任何列都形成一个隐式Group By。 这可能会导致输出的行数超出您的预期。例如:
select * from match_results
pivot (
count(*) for location in (
'Snowley', 'Coldgate', 'Dorwall', 'Newdell'
)
);
MATCH_DATE HOME_TEAM_NAME AWAY_TEAM_NAME HOME_TEAM_POINTS AWAY_TEAM_POINTS 'Snowley' 'Coldgate' 'Dorwall' 'Newdell'
_____________ ____________________ ____________________ ___________________ ___________________ ____________ _____________ ____________ ____________
01-JAN-18 Underrated United Terrible Town 2 0 1 0 0 0
01-JAN-18 Average Athletic Champions City 1 4 0 1 0 0
01-FEB-18 Terrible Town Average Athletic 0 1 0 0 1 0
02-MAR-18 Champions City Terrible Town 8 0 0 0 0 1
01-MAR-18 Average Athletic Underrated United 3 3 0 1 0 0
为避免此情况,需要使用CTE(Common Table Expression)或inline view。CTE就是我们之前的with...as
子句。inline view形式如下:
select * from (select location from match_results)
pivot (
count(*) for location in (
'Snowley', 'Coldgate', 'Dorwall', 'Newdell'
)
);
Expressions
表达式要在CTE或inline view中提取:
with rws as (
select to_char ( match_date, 'MON' ) match_month
from match_results
)
select * from rws
pivot (
count (*) for match_month in (
'JAN', 'FEB', 'MAR'
)
);
'JAN' 'FEB' 'MAR'
________ ________ ________
2 1 2
以下的写法是错误的:
with rws as (
select match_date from match_results
)
select * from rws
pivot (
count (*) for to_char ( match_date, 'MON' ) in (
'JAN', 'FEB', 'MAR'
)
);
Error at Command Line : 6 Column : 27
Error report -
SQL Error: ORA-01738: missing IN keyword
01738. 00000 - "missing IN keyword"
*Cause:
*Action:
Filtering Pivoted Rows
过滤条件需放在pivot子句后面。
例如过滤前:
with rws as (
select location, to_char ( match_date, 'MON' ) match_month
from match_results
)
select * from rws
pivot (
count (*) for match_month in (
'JAN', 'FEB', 'MAR'
)
);
LOCATION 'JAN' 'FEB' 'MAR'
___________ ________ ________ ________
Newdell 0 0 1
Snowley 1 0 0
Coldgate 1 0 1
Dorwall 0 1 0
过滤后:
with rws as (
select location, to_char ( match_date, 'MON' ) match_month
from match_results
)
select * from rws
pivot (
count (*) for match_month in (
'JAN', 'FEB', 'MAR'
)
)
where "'JAN'" > 0;
LOCATION 'JAN' 'FEB' 'MAR'
___________ ________ ________ ________
Snowley 1 0 0
Coldgate 1 0 1
New Column Names
上一节的例子,where条件的写法比较别扭:
where "'JAN'" > 0;
默认情况下,新列的名称是 IN 列表中的值,用引号括起来。 这会使您的 SQL 变得繁琐。 要引用新列,您必须使用双引号括起单引号。
使用别名可以解决此问题:
with rws as (
select location, to_char ( match_date, 'MON' ) match_month
from match_results
)
select * from rws
pivot (
count (*) for match_month in (
'JAN' jan, 'FEB' feb, 'MAR' mar
)
)
where jan > 0;
LOCATION JAN FEB MAR
___________ ______ ______ ______
Snowley 1 0 0
Coldgate 1 0 1
练习答案:
with rws as (
select location,
to_char ( match_date, 'DY' ) match_day
from match_results
)
select * from rws
pivot (
count (*) for match_day in (
'MON' mon, 'TUE' tue , 'WED' wed , 'THU' thu , 'FRI' fri , 'SAT' sat, 'SUN' sun
)
)
where mon >= 1
order by location ;
LOCATION MON TUE WED THU FRI SAT SUN
___________ ______ ______ ______ ______ ______ ______ ______
Coldgate 1 0 0 1 0 0 0
Snowley 1 0 0 0 0 0 0
Pivoting Many Values
可以pivot多个值,只需继续添加聚合函数即可。
with rws as (
select location, to_char ( match_date, 'MON' ) match_month ,
home_team_points, away_team_points
from match_results
)
select * from rws
pivot (
count (*) matches,
sum ( home_team_points ) home_points,
sum ( away_team_points ) away_points
for match_month in (
'JAN' jan, 'FEB' feb, 'MAR' mar
)
);
LOCATION JAN_MATCHES JAN_HOME_POINTS JAN_AWAY_POINTS FEB_MATCHES FEB_HOME_POINTS FEB_AWAY_POINTS MAR_MATCHES MAR_HOME_POINTS MAR_AWAY_POINTS
___________ ______________ __________________ __________________ ______________ __________________ __________________ ______________ __________________ __________________
Newdell 0 0 1 8 0
Snowley 1 2 0 0 0
Coldgate 1 1 4 0 1 3 3
Dorwall 0 1 0 1 0
对于 IN 列表中的每个值,每个新聚合都有一个新列。 所以新列的总数是,即3x3=9:
聚合列数 * IN 列表中值的数量
生成的列名称是: IN 列表标题+各聚合列的别名,例如JAN+MATCHES。
例题答案:
with rws as (
select location, home_team_points, away_team_points
from match_results
)
select * from rws
pivot (
count(*) matches,
sum(home_team_points + away_team_points) points
for location in (
'Snowley' snowley, 'Coldgate' coldgate,
'Dorwall' dorwall, 'Newdell' newdell
)
);
SNOWLEY_MATCHES SNOWLEY_POINTS COLDGATE_MATCHES COLDGATE_POINTS DORWALL_MATCHES DORWALL_POINTS NEWDELL_MATCHES NEWDELL_POINTS
__________________ _________________ ___________________ __________________ __________________ _________________ __________________ _________________
1 2 2 11 1 1 1 8
Dynamic Pivoting
也就是需要IN列表中的值是动态的。
可以使用XML pivoting,但是比较麻烦,次略。
Unpivoting
是pivot的逆过程。
以下SQL按主客队分开,因此行数是表记录的2倍:
select match_date, location, 'HOME' home_or_away, home_team_name team
from match_results
union all
select match_date, location, 'AWAY' home_or_away, away_team_name team
from match_results
order by match_date, location, home_or_away;
MATCH_DATE LOCATION HOME_OR_AWAY TEAM
_____________ ___________ _______________ ____________________
01-JAN-18 Coldgate AWAY Champions City
01-JAN-18 Coldgate HOME Average Athletic
01-JAN-18 Snowley AWAY Terrible Town
01-JAN-18 Snowley HOME Underrated United
01-FEB-18 Dorwall AWAY Average Athletic
01-FEB-18 Dorwall HOME Terrible Town
01-MAR-18 Coldgate AWAY Underrated United
01-MAR-18 Coldgate HOME Average Athletic
02-MAR-18 Newdell AWAY Terrible Town
02-MAR-18 Newdell HOME Champions City
10 rows selected.
Unpivot Clause
以下的写法比上面简洁:
select match_date, location, home_or_away, team
from match_results
unpivot (
team for home_or_away in (
home_team_name as 'HOME', away_team_name as 'AWAY'
)
)
order by match_date, location, home_or_away;
练习答案为:
select match_date, location, home_or_away, points
from match_results
unpivot (
points for
home_or_away in (
home_team_points as 'HOME', away_team_points as 'AWAY'
)
)
order by match_date, location, home_or_away;
环境清理
drop table match_results;
以上是关于Oracle开发者中级第5课(Pivot 和Unpivot)实验的主要内容,如果未能解决你的问题,请参考以下文章