行列转换

1.变换结果集成一行

create table test3
	(
    deptno   int           not null,
	cnt      int           not null
    );
insert into test3 values (10,3);
insert into test3 values (20,5);
insert into test3 values (30,6);
select * from test3;

原数据长这样

我们希望数据这样

一开始这样写的

select 
	sum(case when deptno = 10 then cnt else 0 end) as depno_10
    ,sum(case when deptno = 20 then cnt else 0 end) as depno_20
    ,sum(case when deptno = 30 then cnt else 0 end) as depno_30
from 
	test3
group by deptno;

结果当然不对了,你想想对于deptno=10,depno=10,dept_20=0...

正确做法

select 
	sum(case when deptno = 10 then cnt else 0 end) as depno_10
    ,sum(case when deptno = 20 then cnt else 0 end) as depno_20
    ,sum(case when deptno = 30 then cnt else 0 end) as depno_30
from 
	test3;

第一行=10,所以10=3,20=0,30=0;如上所示,后来sum就行啦

为什么group by就不可以,因为group by之后再sum就是对groupby字段中不同值进行sum,所以第一行只有sum它本身 

groupby的效果:保证对该字段的每个不同的值都当作一行,去执行select里面的操作

所以在这里10,20,30都是不同的值(groupby不仅没得用,而且强制每一行都要执行select里面的操作,有三个操作,所以会有上面=0的情况)但是不groupby直接sum就意味着对10,20,30所有的记录当作一条去执行select里面的操作就行

为了更好说明效果

我再插入两行

insert into test3 values (30,7);
insert into test3 values (30,8);

select 
	sum(case when deptno = 10 then cnt else 0 end) as depno_10
    ,sum(case when deptno = 20 then cnt else 0 end) as depno_20
    ,sum(case when deptno = 30 then cnt else 0 end) as depno_30
from 
	test3
group by deptno;

是这样,对于第一2行都是自己成一个group的,sum相当于不sum

第3,4,5是一起的,不sum的时候(006;007;008),之后sum,得到(0021)

select 
	sum(case when deptno = 10 then cnt else 0 end) as depno_10
    ,sum(case when deptno = 20 then cnt else 0 end) as depno_20
    ,sum(case when deptno = 30 then cnt else 0 end) as depno_30
from 
	test3;

得到正确的结果

3,5,21

xi

2.变换结果集成多行

create table test2
	(
    empno   int           not null,
	job     varchar(15)   not null,
    ename   varchar(15)   not null
    );
insert into test2 values (1,'A','linda');
insert into test2 values (2,'A','alice');
insert into test2 values (3,'A','juice');
insert into test2 values (4,'B','kris');
insert into test2 values (5,'B','gem');

原数据长这样

最后希望得到这样的结果

一开始本?是这样做的

select 
	case when job = 'A' then ename else null end as 'jobA'
    ,case when job = 'B' then ename else null end as 'jobB'
from
	test2;

结果是这个样子,当然不对了!你对每一行都问下case=A吗,case=B吗,所以第一条记录job A有,jobB没有

正确做法

select 
     max(case when job = 'A' then ename else null end) as 'jobA'
    ,max(case when job = 'B' then ename else null end) as 'jobB'
from
	(
    select
         a.job
        ,a.ename
        ,(select count(*) from test2 as b
         where b.job = a.job and a.empno < b.empno) as rnk
	from 
		test2 as a
	) as x
group by rnk; 

注意a.job=b.job and a.empno<b.empno;是分组(分job)排序哦!!!!

哇 这样保证rnk相同的时候都是不同类型的job,这个时候casewhen就很棒,max只是为了从结果集中剔除null 

再次感受groupby:这里对每个不同的rnk保证一行,去执行select。所以最后结果只有rnk=0的情况rnk=1/rnk=2的情况,也就是说只有三行!!!!!!!!。对于rnk=0(Job=a,job=b有2种情况,但没关系,我们还是当作一行)执行select的第一个=a那么就是ename,=b就不执行了;同理第二个条件;这样保证有2列了!

当然如果可以使用窗口函数更好

 

select 
     max(case when job = 'A' then ename else null end) as 'jobA'
    ,max(case when job = 'B' then ename else null end) as 'jobB'
from
	(
    select
         a.job
        ,a.ename
        ,row_number()over(partition by job order by ename) as rnk
	from 
		test2 
	) as x
group by rnk; 

3.反向变换结果

原来

现在 

这个时候要用笛卡尔积 

注意笛卡尔积必须是一列值才可以(行数成倍增加),一行值形成不了

比如下面这样子可以形成笛卡尔积

select 
	*
from 
	(
	select 
		sum(case when deptno = 10 then cnt else 0 end) as depno_10
		,sum(case when deptno = 20 then cnt else 0 end) as depno_20
		,sum(case when deptno = 30 then cnt else 0 end) as depno_30
	from 
	test3
    ) as a
	,(select deptno from test3) as c
;

select 
	c.deptno
    ,(case when c.deptno = 10 then depno_10
          when c.deptno = 20 then depno_20
          else depno_30
          end) as cnt
from 
	(
	select 
		sum(case when deptno = 10 then cnt else 0 end) as depno_10
		,sum(case when deptno = 20 then cnt else 0 end) as depno_20
		,sum(case when deptno = 30 then cnt else 0 end) as depno_30
	from 
	test3
    ) as a
	,(select deptno from test3) as c
;

这样写就对啦~~ 

上面这种形式的迪卡尔积是有真实意义的,

但有时候你就是想为你原始的数据增加每行都直接扩大X倍,这个时候你只需要将笛卡尔积取的另外一个列保证有四行就可以(数值什么的不重要)详细见sql经典实例第12章340页

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值