我在接受采访时被问到这个问题,我已经知道我们可以使用CASE / oracle的最大功能了。 但面试官想要一个答案,如果添加新列,我们不必更改查询。 e.g
Student English history maths
zzzz 85 55 66
yyyy 47 99 55
预期结果: -
zzzzz English :85
yyyyy history :99
现在,如果表被更改,则同一查询应该起作用
Student English history maths science
zzzz 85 55 66 86
yyyy 47 99 55 11
预期结果: -
zzzzz science :86
yyyyy history :99
答案 0 :(得分:2)
您可以使用unpivot在Oracle中获得答案:
SELECT *
FROM (
SELECT t.*,
ROW_NUMBER() OVER ( PARTITION BY student ORDER BY total DESC ) AS rn
FROM your_table
UNPIVOT ( total FOR subject IN ( english, maths, history ) ) t
)
WHERE rn = 1;
但您需要将新列名称添加到IN
的{{1}}子句中。
但是,如果您要使用动态SQL,那么您可以使用数据字典(即UNPIVOT
表)构建查询的那一部分:
USER_TAB_COLUMNS
答案 1 :(得分:1)
在Oracle中,您可以在不case
的情况下执行此操作。取消透视和排序数据:
select student, subject, result
from (select student, subject, result,
rank() over (partition by student order by result desc) rnk
from t
unpivot (result for subject in (english, history, maths, science)))
where rnk = 1
演示:
with t(student, english, history, maths, science) as (
select 'zzzz', 85, 55, 66, 86 from dual union all
select 'yyyy', 47, 99, 55, 11 from dual )
select student, subject, result
from (select student, subject, result,
rank() over (partition by student order by result desc) rnk
from t
unpivot (result for subject in (english, history, maths, science)))
where rnk = 1
STUDENT SUBJECT RESULT
------- ------- ----------
yyyy HISTORY 99
zzzz SCIENCE 86
无论如何,你必须在unpivot条款中列出主题。要省略这一点,您必须使用dynamic sql。
答案 2 :(得分:1)
您可以通过XML结构反弹来解开表格:
create table scores (student, english, history, maths) as
select 'zzzz', 85, 55, 66 from dual
union all select 'yyyy', 47, 99, 55 from dual;
select x.student,
max(x.subject) keep (dense_rank last order by x.score) as subject,
max(x.score) as score
from (
select dbms_xmlgen.getxml('select student, ''' || column_name || ''' as subject, '
|| column_name || ' as score from ' || table_name) as xml_clob
from user_tab_columns
where table_name = 'SCORES'
and column_name != 'STUDENT'
) t
cross join xmltable (
'//ROWSET/ROW'
passing xmltype(t.xml_clob)
columns student varchar2(8) path 'STUDENT',
subject varchar2(30) path 'SUBJECT',
score number path 'SCORE'
) x
group by x.student;
STUDENT SUBJECT SCORE
-------- ------------------------------ ----------
yyyy HISTORY 99
zzzz ENGLISH 85
更改表格后添加额外的列:
alter table scores add (science number);
update scores set science = 86 where student = 'zzzz';
update scores set science = 11 where student = 'yyyy';
相同的查询得到:
STUDENT SUBJECT SCORE
-------- ------------------------------ ----------
yyyy HISTORY 99
zzzz SCIENCE 86
最里面的部分生成XML,每个学生/列名称/值都转换为元素:
select dbms_xmlgen.getxml('select student, ''' || column_name || ''' as subect, '
|| column_name || ' as score from ' || table_name)
from user_tab_columns
where table_name = 'SCORES'
and column_name != 'STUDENT';
<?xml version="1.0"?>
<ROWSET>
<ROW>
<STUDENT>zzzz</STUDENT>
<SUBECT>ENGLISH</SUBECT>
<SCORE>85</SCORE>
</ROW>
...
然后,XMLTable将其转换回关系数据:
select x.*
from (
select dbms_xmlgen.getxml('select student, ''' || column_name || ''' as subject, '
|| column_name || ' as score from ' || table_name) as xml_clob
from user_tab_columns
where table_name = 'SCORES'
and column_name != 'STUDENT'
) t
cross join xmltable (
'//ROWSET/ROW'
passing xmltype(t.xml_clob)
columns student varchar2(8) path 'STUDENT',
subject varchar2(30) path 'SUBJECT',
score number path 'SCORE'
) x;
STUDENT SUBJECT SCORE
-------- ------------------------------ ----------
zzzz ENGLISH 85
yyyy ENGLISH 47
zzzz HISTORY 55
yyyy HISTORY 99
zzzz MATHS 66
yyyy MATHS 55
zzzz SCIENCE 86
yyyy SCIENCE 11
然后它只是一个聚合问题......