zoukankan      html  css  js  c++  java
  • oracle10g没有行列转换函数的替代方法(转)

    在oracle示例数据库scott下执行

    select empno,ename,job,sal,deptno from emp 
    order by deptno,job;

    --行转列
    --现在查询各部门各工种的总薪水

    select deptno, job, sum(sal) total_sal from emp 
    group by deptno, job order by 1, 2;

    --但是这样不直观,如果能够把每个工种作为1列显示就会更一目了然.
    --这就是需要行转列。
    --在11g之前,需要一点技巧,利用decode函数才能完成这个目标。

    复制代码
    select deptno, 
    sum(decode(job, 'PRESIDENT', sal, 0)) as PRESIDENT_SAL, 
    sum(decode(job, 'MANAGER', sal, 0)) as MANAGER_SAL, 
    sum(decode(job, 'ANALYST', sal, 0)) as ANALYST_SAL, 
    sum(decode(job, 'CLERK', sal, 0)) as CLERK_SAL, 
    sum(decode(job, 'SALESMAN', sal, 0)) as SALESMAN_SAL 
    from emp group by deptno order by 1; 
    复制代码
    复制代码
    select deptno, 
    sum(case when job='PRESIDENT' then sal else 0 end) as PRESIDENT_SAL, 
    sum(case when job='MANAGER' then sal else 0 end) as MANAGER_SAL, 
    sum(case when job='ANALYST' then sal else 0 end) as ANALYST_SAL, 
    sum(case when job='CLERK' then sal else 0 end) as CLERK_SAL, 
    sum(case when job='SALESMAN' then sal else 0 end) as SALESMAN_SAL 
    from emp group by deptno order by 1; 
    复制代码

     

    --如果要在变回前面的结果,需要用到笛卡尔乘积,一行变五行,然后利用decode。例如:

    复制代码
    with t as ( 
    select deptno, 
    sum(decode(job, 'PRESIDENT', sal, 0)) as PRESIDENT_SAL, 
    sum(decode(job, 'MANAGER', sal, 0)) as MANAGER_SAL, 
    sum(decode(job, 'ANALYST', sal, 0)) as ANALYST_SAL, 
    sum(decode(job, 'CLERK', sal, 0)) as CLERK_SAL, 
    sum(decode(job, 'SALESMAN', sal, 0)) as SALESMAN_SAL 
    from emp group by deptno 
    ) 
    select deptno, 
    decode(lvl, 1, 'PRESIDENT', 2, 'MANAGER', 3, 'ANALYST', 
    4, 'CLERK', 5, 'SALESMAN') as JOB, 
    decode(lvl, 1, PRESIDENT_SAL, 2, MANAGER_SAL, 3, ANALYST_SAL, 
    4, CLERK_SAL, 5, SALESMAN_SAL) as TOTAL_SAL 
    from t, (select level lvl from dual connect by level <= 5) 
    order by 1, 2;
    复制代码

    --11g之后,oracle增加了pivot和unpivot语句,可以很方便的完成这个转换。
    --pivot
    --先来看看pivot的语法是

    复制代码
    SELECT .... 
    FROM <table-expr> 
    PIVOT 
    ( 
    aggregate-function(<column>) 
    FOR <pivot-column> IN (<value1>, <value2>,..., <valuen>) 
    ) AS <alias> 
    WHERE .....
    复制代码

     

    复制代码
    select * from 
    (select deptno, job, sal from emp) 
    pivot( 
    sum(sal) for job in ( ---IN后面的值转化为列名 实际转换:sum(case when job='PRESIDENT' then sal else 0 end) as PRESIDENT_SAL
    'PRESIDENT' as PRESIDENT_SAL, 
    'MANAGER' as MANAGER_SAL, 
    'ANALYST' as ANALYST_SAL, 
    'CLERK' as CLERK_SAL, 
    'SALESMAN' as SALESMAN_SAL 
    ) 
    ) order by 1;
    复制代码

    --实际上,oracle对pivot子句中出现的列以外的列做了一个隐式的group by.
    --现在,如果想要再结果中增加1列,显示部门的薪水总合,可以这么做

    复制代码
    select * from 
    (select deptno, sum(sal) over (partition by deptno) SAL_TOTAL, job, sal from emp) 
    pivot( 
    sum(sal) as SAL_TOTAL for job in ( 
    'PRESIDENT' as PRESIDENT, 
    'MANAGER' as MANAGER, 
    'ANALYST' as ANALYST, 
    'CLERK' as CLERK, 
    'SALESMAN' as SALESMAN 
    ) 
    ) order by 1; 
    复制代码

    --2点说明,
    --1)oracle对pivot子句中出现的列以外的列,也就是deptno和SAL_TOTAL做了隐式的group by.
    -- 这里用了分析函数,对于每个deptno,SAL_TOTAL是唯一的,所以group by的结果还是3行。

    复制代码
    select * from 
    (select deptno, job, sal from emp) 
    pivot( 
    sum(sal) as SAL_TOTAL, count(sal) as EMP_TOTAL for job in ( --实际转换:sum(case when job='CLERK' then sal else 0 end) as CLERK_SAL_TOTAL
    --count(case when job='CLERK' then sale end) as CLERK_EMP_TOTAL
    'CLERK' as CLERK, 
    'SALESMAN' as SALESMAN 
    ) 
    ) order by 1;  
    复制代码

    -2)oracle会拼接列名 = for字句中别名+聚合函数别名,比如'PRESIDENT'+'_'+'SAL_TOTAL'。

    --可以指定多个聚合函数,例如统计薪水总合和人数总合:

    复制代码
    select deptno,
    sum(case when job='CLERK' then sal else 0 end) as CLERK_SAL_TOTAL,
    count(case when job='CLERK' then sal end) as CLERK_EMP_TOTAL,
    sum(case when job='SALESMAN' then sal else 0 end) as SALESMAN_SAL_TOTAL,
    count(case when job='SALESMAN' then sal end) as SALESMAN_EMP_TOTAL
    from emp
    group by deptno
    order by 1;
    复制代码

    --for子句可以指定多列,
    --为此,先给emp表追加1列rank,取值为'A','B',

    alter table emp add (rank varchar2(1) default('A')); 
    update emp set rank=decode(mod(rownum, 2), 0, 'B', rank);
    
    select deptno, job, rank, count(sal) as EMP_TOTAL from emp 
    group by deptno, job, rank order by 1, 2; 

    --现在,想统计SALESMAN和CLERK的员工中,rank A和rank B各自的人数

    复制代码
    select * from 
    (select deptno, job, rank from emp) 
    pivot( 
    count(rank) as EMP_TOTAL for (job, rank) in ( --实际转换:sum(case when job='SALESMAN' and rank='A' then count(rank) else 0 end) as SALESMAN_A
    ('SALESMAN', 'A') as SALESMAN_A, 
    ('SALESMAN', 'B') as SALESMAN_B, 
    ('CLERK', 'A') as CLERK_A, 
    ('CLERK', 'B') as CLERK_B 
    ) 
    ) order by 1; 
    复制代码



    --列转行
    --unpivot的语法:

    复制代码
    SELECT .... 
    FROM <table-expr> 
    UNPIVOT [include nulls|exclude nulls] 
    ( 
    (<column>) 
    FOR <pivot-column> IN (<value1>, <value2>,..., <valuen>) 
    ) AS <alias> 
    WHERE .....
    复制代码

    --用unpivote语句来做列到行的转换

    复制代码
    with t as ( 
    select * from 
    (select deptno, job, sal from emp) 
    pivot( 
    sum(sal) for job in ( 
    'CLERK' as CLERK_SAL, 
    'SALESMAN' as SALESMAN_SAL 
    ) 
    ) 
    ) 
    select * from t 
    unpivot( 
    SAL_TOTAL for JOB in ( --以JOB为列名,存放IN后面的值,SAL_TOTAL为列
    CLERK_SAL as 'CLERK', 
    SALESMAN_SAL as 'SALESMAN' 
    ) 
    ) order by 1,2; 
    复制代码

    ---如果加上include nulls子句

    复制代码
    with t as ( 
    select * from 
    (select deptno, job, sal from emp) 
    pivot( 
    sum(sal) for job in ( 
    'CLERK' as CLERK_SAL, 
    'SALESMAN' as SALESMAN_SAL 
    ) 
    ) 
    ) 
    select * from t 
    unpivot include nulls( 
    SAL_TOTAL for JOB in ( 
    CLERK_SAL as 'CLERK', 
    SALESMAN_SAL as 'SALESMAN' 
    ) 
    ) order by 1,2;
    复制代码

    --可以指定多个pivot-column

    复制代码
    with t as ( 
    select * from 
    (select deptno, job, sal from emp) 
    pivot( 
    sum(sal) as SAL_TOTAL, count(sal) as EMP_TOTAL for job in ( 
    'CLERK' as CLERK, 
    'SALESMAN' as SALESMAN 
    ) 
    ) 
    ) 
    select * from t 
    unpivot include nulls( 
    (SAL_TOTAL, EMP_TOTAL) for JOB in ( 
    (CLERK_SAL_TOTAL, CLERK_EMP_TOTAL) as 'CLERK', 
    (SALESMAN_SAL_TOTAL, SALESMAN_EMP_TOTAL) as 'SALESMAN' 
    ) 
    ) order by 1,2; 
    复制代码

    ---返回XML格式数据

    select * from 
    (select deptno, job, sal from emp) 
    pivot XML( 
    sum(sal) for job in (ANY) 
    ) order by 1; 
  • 相关阅读:
    手机端和电脑端左右分屏录制视频解决方法
    收藏 网站部署配置文章
    廖雪峰网站:学习python函数—递归函数(四)
    廖雪峰网站:学习python函数—函数参数(三)
    廖雪峰网站:学习python函数—定义函数(二)
    廖雪峰网站:学习python函数—调用函数(一)
    廖雪峰网站:学习python基础知识—循环(四)
    廖雪峰网站:学习python基础知识—判断(三)
    Java提高十七:TreeSet 深入分析
    Java提高十六:TreeMap深入分析
  • 原文地址:https://www.cnblogs.com/CryOnMyShoulder/p/7644697.html
Copyright © 2011-2022 走看看