从表的colomns检查最大值,表colomn未知/常量

时间:2017-08-21 10:34:51

标签: mysql sql oracle

我在接受采访时被问到这个问题,我已经知道我们可以使用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

3 个答案:

答案 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

然后它只是一个聚合问题......