设为首页 收藏本站
查看: 529|回复: 0

[经验分享] sql server和oracle 行列转换

[复制链接]

尚未签到

发表于 2016-8-4 12:45:12 | 显示全部楼层 |阅读模式
  1. 行列转换--普通

假设有张学生成绩表(CJ)如下
Name Subject Result
张三 语文 80
张三 数学 90
张三 物理 85
李四 语文 85
李四 数学 92
李四 物理 82

想变成
姓名 语文 数学 物理
张三 80 90 85
李四 85 92 82

  测试: --by yanleigis email:landgis@126.com

create table CJ
(
id int IDENTITY(1,1) not null primary key, --自增加1
Name varchar(8),
Subject varchar(8),
Result float
)

  alter table cj alter column result numeric(8,1) --设置小数位数
insert into CJ (Name,Subject,Result) values ('张三','语文',80)
insert into CJ (Name,Subject,Result) values ('张三', '数学', 90)
insert into CJ (Name,Subject,Result) values ('张三','物理', 85)
insert into CJ (Name,Subject,Result) values ('李四','语文', 85)
insert into CJ (Name,Subject,Result) values ('李四','数学', 92)
insert into CJ (Name,Subject,Result) values ('李四', '物理', 82)

declare @sql varchar(4000)
set @sql = 'select Name'
select @sql = @sql + ',sum(case Subject when '''+Subject+''' then Result end) ['+Subject+']'
from (select distinct Subject from CJ) as a
select @sql = @sql+' from cj group by name'
PRINT @sql --打印变量的值,注释两种方法--,/**/
exec(@sql)
select Name,sum(case Subject when '数学' then Result end) [数学],sum(case Subject when '物理' then Result end) [物理],sum(case Subject when '语文' then Result end) [语文] from cj group by name

  
2. 行列转换--合并

有表A,
id pid
1 1
1 2
1 3
2 1
2 2
3 1
如何化成表B:
id pid
1 1,2,3
2 1,2
3 1

创建一个合并的函数
create function fmerg(@id int)
returns varchar(8000)
as
begin
declare @str varchar(8000)
set @str=''
select @str=@str+','+cast(pid as varchar) from 表A where id=@id set @str=right(@str,len(@str)-1)
return(@str)
End
go

--调用自定义函数得到结果
select distinct id,dbo.fmerg(id) from 表A
  测试:
  create table 表A
(
id int,
pid int)
  insert into 表A values (1,1);
insert into 表A values (1,2);
insert into 表A values (1,3);
insert into 表A values (2,1);
insert into 表A values (2,2);
insert into 表A values (3,1);
  create function fmerg(@id int)
returns varchar(8000)
as
begin
declare @str varchar(8000)
set @str=''
select @str=@str+','+cast(pid as varchar) from 表A where id=@id set @str=right(@str,len(@str)-1)
return(@str)
End
go
  select distinct id,dbo.fmerg(id) from 表A

  来自:http://www.cnblogs.com/stu-acer/archive/2006/05/16/401445.html


下面的是Oracle行列转换实战(转载)
   行列转换实例
DSC0000.gif 表ttt有三个字段
seq--序列
jcxm--检查项目
zhi--值

数据分别如下:
seq   jcxm  zhi
-----------------------
11     1    0.50
11     2    0.21
11     3    0.25
12     1    0.24
12     2    0.30
12     3    0.22

实现功能
创建视图时移动行值为列值


createviewv_view1
as
selectseq,
sum(decode(jcxm,1,zhi))检测项目1,
sum(decode(jcxm,2,zhi))检测项目2,
sum(decode(jcxm,3,zhi))检测项目3
fromttt
groupbyseq;

序号检测项目1  检测项目2  检测项目3
11     0.50    0.21     0.25
12     0.24    0.30     0.22



技巧:
用THEN中的0和1来进行统计(SUM)

jcxmzhi
--------
a1
b1
a3
d2
e4
f5
a5
d3
d6
b5
c4
b3
求他的zhi既是1,也是3,也是5的jcxm
方法一
selectjcxm
fromttt
groupbyjcxm
havingsum(decode(zhi,1,-1,3,-1,5,-1,0))=-3
方法二
selectjcxmfromttt
groupbyjcxmhaving(sign(sum(decode(zhi,1,-1,0)))+
sign(sum(decode(zhi,3,-1,0)))+sign(sum(decode(zhi,5,-1,0)))<=-3);

----------
a
b
说明:
sign()函数根据某个值是0、正数还是负数,分别返回0、1、-1
所以可以用sign和decode来完成比较字段大小来区某个字段
selectdecode(sign(字段1-字段2),-1,字段3,字段4)fromdual;

sign是一个对于写分析SQL有很强大的功能
下面我对sign进行一些总结:
但属性student取0和1以外的值,或者student取两个以上的标法值,问题就不会这么简单了
解决办法就是特征函数(abs(),sign())

常用的特征算法
[A=B]=1-abs(sign(A-B))
[A!=B]=abs(sign(A-B))
[A<B]=1-sign(1+sign(A-B))
不能用-sign(A-B):因为如果不满足A<b则返回-1,而不是0,这样就不能用在字段选择上了
[A<=B]=sign(1-sign(A-B))
[A>B]=1-sign(1-sign(A-B))
[A>=B]=sign(1+sign(A-B)))
[NOTα]=1-d[α]
[αANDb]=d[α]*d[b](6)
[αORb]=sign(d[α]+d

例如:
A<BDecode(Sign(A-B),-1,1,0)

A<=BDecode(Sign(A-B),1,0,1)

A>BDecode(Sign(A-B),1,1,0)

A>=BDecode(Sign(A-B),-1,0,1)

A=BDecode(A,B,1,0)
AbetweenBandCDecode(Sign(A-B),-1,0,
Decode(Sign(A-C),1,0,1))
AisnullDecode(A,null,1,0)
AisnotnullDecode(A,null,0,1)Ain
(B1,B2, DSC0001.gif ,Bn)Decode(A,B1,1,B2,1,,Bn,1,0)
norLogADecode(LogA,0,1,0)
(1-Sign(LogA))
LogAandLogBLogA*LogB
LogAorLogBLogA+LogB
LogAxorLogBDecode(Sign(LogA),Sign(LogB),0,1)
Mod(Sign(LogA),Sign(LogB),2


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

[NextPage]
另外一个关于成绩的分析例子

SELECT
SUM(CASEWHENcj<60THEN1ELSE0END)as"notpassed",
SUM(CASEWHENcjBETWEEN60AND79THEN1ELSE0END)as
"passed",
SUM(CASEWHENcjBETWEEN80AND89THEN1ELSE0END)as
"good",
SUM(CASEWHENcj>=90THEN1ELSE0END)as"Excellent"
FROMcjtable;

decode用法2
表、视图结构转化
现有一个商品销售表sale,表结构为:
month   char(6)     --月份
sell    number(10,2)   --月销售金额

现有数据为:
200001  1000
200002  1100
200003  1200
200004  1300
200005  1400
200006  1500
200007  1600
200101  1100
200202  1200
200301  1300

想要转化为以下结构的数据:
year   char(4)     --年份
---------------------------------
-------------------
month1  number(10,2)   --1月销售金额
month2  number(10,2)   --2月销售金额
month3  number(10,2)   --3月销售金额
month4  number(10,2)   --4月销售金额
month5  number(10,2)   --5月销售金额
month6  number(10,2)   --6月销售金额
month7  number(10,2)   --7月销售金额
month8  number(10,2)   --8月销售金额
month9  number(10,2)   --9月销售金额
month10 number(10,2)  --10月销售金额
month11 number(10,2)  --11月销售金额
month12 number(10,2)  --12月销售金额

结构转化的SQL语句为:
createorreplaceview
v_sale(year,month1,month2,month3,month4,month5,month6,month7,month8,month9,month10,month11,month12)
as
    select
    substrb(month,1,4),
    sum(decode(substrb(month,5,2),'01',sell,0)),
    sum(decode(substrb(month,5,2),'02',sell,0)),
    sum(decode(substrb(month,5,2),'03',sell,0)),
    sum(decode(substrb(month,5,2),'04',sell,0)),
    sum(decode(substrb(month,5,2),'05',sell,0)),
    sum(decode(substrb(month,5,2),'06',sell,0)),
    sum(decode(substrb(month,5,2),'07',sell,0)),
    sum(decode(substrb(month,5,2),'08',sell,0)),
    sum(decode(substrb(month,5,2),'09',sell,0)),
    sum(decode(substrb(month,5,2),'10',sell,0)),
    sum(decode(substrb(month,5,2),'11',sell,0)),
    sum(decode(substrb(month,5,2),'12',sell,0))
    fromsale
    groupbysubstrb(month,1,4);

体会:要用decode/groupby/orderby/sign/sum来实现不同报表的生成
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CASE应用

11部门a800男
22部门b900女
33部门a400男
44部门d1400女
55部门e1200男
66部门f500男
77部门a300女
88部门d1000男
99部门d1230女
1010部门b2000女
1111部门c2000男
1212部门b1200男

SELECTjcxmas部门,COUNT(seq)as人数,
SUM(CASESEXWHEN1THEN1ELSE0END)as男,
SUM(CASESEXWHEN2THEN1ELSE0END)as女,
SUM(CASESIGN(zhi-800)WHEN-1THEN1ELSE0END)as
小于800元,
SUM((CASESIGN(zhi-800)*SIGN(zhi-1000)
DSC0002.gif DSC0003.gif /**//*用*来实现<和>功能*/
WHEN-1THEN1ELSE0END)+(CASEzhi
WHEN800THEN1ELSE0END))as从800至999,
/**//*注意别名不能以数字开头*/
SUM((CASESIGN(zhi-1000)*SIGN(zhi-1200)
WHEN-1THEN1ELSE0END)+(CASEzhi
WHEN1000THEN1ELSE0END))as从1000元至1199元,
SUM((CASESIGN(zhi-1200)WHEN1THEN1ELSE0END)
+(CASEzhiWHEN1200THEN1ELSE0END))as大于1200元
FroMttt
GROUPBYjcxm

部门名人数男女小于800元从800至999从1000元至1199元大于1200元
部门a321210
0
部门b312010
2
部门c110000
1
部门d312001
2
部门e110000
1
部门f110100
0


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-252760-1-1.html 上篇帖子: Oracle dbms_job package 用法小结 下篇帖子: Oracle 10g Dynamic report column(eg)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表