PL/SQL Challenge 每日一题:2016-8-12 行列转换

[复制链接]
查看11 | 回复9 | 2008-9-15 01:28:12 | 显示全部楼层 |阅读模式
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。
每两周的优胜者可获得itpub奖励的技术图书一本。
以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808
原始出处:
http://www.plsqlchallenge.com/
作者:
Kim Berg Hansen
运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品
我有一张汽车的表,里面有诸如厂家、型号、类型等属性。不幸的是应用设计者喜欢EAV(Entity-Attribute-Value)数据模型,在这种模型中,这种属性被独立地存在一张表中,每个属性的name/value为一行:
create table plch_cars (
id
integer primary key
, namevarchar2(30)
)
/
create table plch_attributes (
car_idinteger references plch_cars
, attribute varchar2(10)
, value varchar2(30)
, constraint plch_attributes_pk primary key (car_id, attribute)
)
/
insert into plch_cars values (1, 'Model X SUV from Tesla')
/
insert into plch_cars values (2, 'Edge SUV from Ford')
/
insert into plch_cars values (3, 'Malibu Sedan from Chevrolet')
/
insert into plch_attributes values (1, 'MAKE' , 'Tesla')
/
insert into plch_attributes values (1, 'MODEL', 'Model X')
/
insert into plch_attributes values (1, 'TYPE' , 'SUV')
/
insert into plch_attributes values (2, 'MAKE' , 'Ford')
/
insert into plch_attributes values (2, 'MODEL', 'Edge')
/
insert into plch_attributes values (2, 'TYPE' , 'SUV')
/
insert into plch_attributes values (3, 'MAKE' , 'Chevrolet')
/
insert into plch_attributes values (3, 'MODEL', 'Malibu')
/
insert into plch_attributes values (3, 'TYPE' , 'Sedan')
/
commit
/
应用开发者保证这个应用会强制每辆车的每个MAKE, MODEL 和 TYPE属性都恰好有一行记录(既不会是零行,也不会多于一行)(我没有SQL断言,我相信他们是对的)
我想要一个报表显示汽车(id和名字),按照"type, make, model"顺序排列,不分大小写。如果这三个属性是car表中的三个列,那我就简单地这么写(假设的,并不是真的能用):
select id, name
from plch_cars
order by upper(type), upper(make), upper(model)
/
但是既然我没有这样的列,我需要写个查询来模拟这种行为,从plch_attributes表中得到需要排序的属性值。
哪些选项包含的查询会把汽车按照他们的属性值以上述方式排序,让我得到这个输出:
ID NAME
---------- ------------------------------
3 Malibu Sedan from Chevrolet
2 Edge SUV from Ford
1 Model X SUV from Tesla
(A)
select c.id, c.name
from plch_cars c
order by ( select upper(a.value)

from plch_attributes a

where a.car_id = c.id

and a.attribute = 'TYPE' )
, ( select upper(a.value)

from plch_attributes a

where a.car_id = c.id

and a.attribute = 'MAKE' )
, ( select upper(a.value)

from plch_attributes a

where a.car_id = c.id

and a.attribute = 'MODEL' )
/
(B)
select c.id, c.name
from plch_cars c
order by (

select listagg(rpad(upper(a.value), 30)) within group (

order by case a.attribute

when 'TYPE'then 1

when 'MAKE'then 2

when 'MODEL' then 3

end

)

from plch_attributes a

where a.car_id = c.id

and a.attribute in ('MAKE', 'MODEL', 'TYPE')

)
/
(C)
select c.id, c.name
from plch_cars c
join (
select a.car_id

, listagg(rpad(upper(a.value), 30)) within group (

order by case a.attribute

when 'TYPE'then 1

when 'MAKE'then 2

when 'MODEL' then 3

end

) order_string
from plch_attributes a

where a.attribute in ('MAKE', 'MODEL', 'TYPE')

group by a.car_id
) ordering
on ordering.car_id = c.id
order by ordering.order_string
/
(D)
select c.id, c.name
from plch_cars c
join (
select car_id

, row_number() over (order by type, make, model) rn
from plch_attributes a

pivot (

max(upper(value))

for attribute in (

'MAKE'as make

, 'MODEL' as model

, 'TYPE'as type

)

)
) ordering
on ordering.car_id = c.id
order by ordering.rn
/
(E)
select c.id, c.name
from plch_cars c
join plch_attributes make
on make.car_id = c.id
and make.attribute = 'MAKE'
join plch_attributes model
on model.car_id = c.id
and model.attribute = 'MODEL'
join plch_attributes type
on type.car_id = c.id
and type.attribute = 'TYPE'
order by upper(type.value)
, upper(make.value)
, upper(model.value)
/
(F)
select c.id, max(c.name) as name
from plch_cars c
join plch_attributes a
on a.car_id = c.id
and a.attribute in ('MAKE', 'MODEL', 'TYPE')
group by c.id
order by max(case a.attribute when 'TYPE'then upper(a.value) end)
, max(case a.attribute when 'MAKE'then upper(a.value) end)
, max(case a.attribute when 'MODEL' then upper(a.value) end)
/
(G)
select id, name
from plch_cars c
join plch_attributes a
on a.car_id = c.id
and a.attribute in ('MAKE', 'MODEL', 'TYPE')
pivot (
max(upper(value))
for attribute in (
'MAKE'as make
, 'MODEL' as model
, 'TYPE'as type
)
)
order by type
, make
, model
/

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
好像测试结果,是ABCDEFG。
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
本帖最后由 534058389 于 2016-8-17 15:55 编辑
534058389 发表于 2016-8-17 15:51
好像测试结果,是ABCDEFG。

order by (

select listagg(rpad(upper(a.value), 30)) within group (

order by case a.attribute

when 'TYPE'then 1

when 'MAKE'then 2

when 'MODEL' then 3

end

)
我在测试listagg函数的时候,order by case 选定结果在未选定结果集前面。输出数字1,2,3并无实质意义。
不知道我的理解对不对。

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
看懂这题就基本不用担心不会行列转换了
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
〇〇 发表于 2016-8-17 21:00
看懂这题就基本不用担心不会行列转换了

是啊,涉及挺多的,还有些细节还没弄清楚,还得查查资料做做实验。
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
答案ABCDEFG, 2楼得奖。
A:
题目中给出的假想查询可以这样实现:将每个不存在的列type, make 和 model用一个标量子查询进行替换。简单且直观,但是大多数情况下不是性能最好的。
B: 我们可以在attributes表上使用一个子查询,利用LISTAGG来创建一个单个字符串,每个属性值都以正确的顺序出现在字符串中。然后我们就可以用这个字符串对汽车进行排序。
C: 不同于前一选项在ORDER BY子句中使用一个相关子查询,我们还可以在一个内联视图中为所有汽车一下子生成排序字符串,然后我们把汽车表连接到这个内联视图来得到每辆车的排序字符串。
D: 除了创建一个长字符串来排序,我们可以将属性表行专列,为每辆车得到一行,列别名为make, model 和 type。然后我们可以在分析函数ROW_NUMBER的ORDER BY子句中使用这些列名得到一个数字RN, 我们可以用它来对汽车表排序。
E: 这使用了三个到attributes表的连接,为每个感兴趣的属性分别获取一行。然后ORDER BY就很容易了。
F: 除了用三个连接,我们可以做一个连接,它为每辆车得到三行。然后我们用GROUP BY把它变成一行,然后用恰当的MAX函数调用进行排序。
G: 前一选项中的MAX(CASE...)结构看起来很像你在版本11G之前的行转列方法。从11G开始我们可以用PIVOT做同样的事,代码可能多一点,但是如果你懂得PIVOT语法,这看起来解释得比较清楚。

回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
534058389 发表于 2016-8-17 15:53
order by (

select listagg(rpad(upper(a.value), 30)) within group (

...

1,2,3很有意义,就是为了在拼字符串的时候严格按照 类型、厂商、型号来排列。
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
截止到今日每日一题奖励已发,辛苦newkid大师
本期从7-30到8-12期
每10期题目发一次奖,10期内获奖最多的再奖励一本技术图书~原有的秀才系列徽章继续根据兑换规则兑换礼品~
大家多多努力哦~
本期获奖情况如下:(其中8-8、8-8、8-10、8-11期无人获奖)
佚名是译名
佚名是译名
PcOYe
wmxcn2000
wmxcn2000
534058389
恭喜佚名是译名、wmxcn2000同学获得一本技术图书,图书徽章已发,可以到书单换任意一本~
各位童鞋继续加油哦~
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层


终于有一个图书徽章了
回复

使用道具 举报

千问 | 2008-9-15 01:28:12 | 显示全部楼层
newkid 发表于 2016-8-18 03:42
答案ABCDEFG, 2楼得奖。
A:

好像以前有这样的规定,需要说明一下为什么是答案XXX
像这样的题目,只要执行一下就能知道答案
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题

0

回帖

4882万

积分

论坛元老

Rank: 8Rank: 8

积分
48824836
热门排行