日期:2014-05-18  浏览次数:20437 次

SQL 2008中多行转多列
RT:测试数据如下
表1
docentry cardcode docdate docduedate
1 A001 2012-01-01 2012-03-25
2 A001 2012-03-27 2012-03-31
3 B001 2012-05-01 2012-05-07
4 C001 2012-05-20 2012-06-15
表2
docentry itemcode price
1 ak-530 10
1 ak-cc 8
2 ak-530 99
3 mp-a52 7
4 ak-530 25

需求结果:
itemcode docdate docduedate A001 DOCDATE DOCDUEDATE C001  
ak-530 2012-03-27 2012-03-31 99 2012-05-20 2012-06-15 25
就是需要按不同厂商(cardcode)相同物料号(itemcode)与最近的DOCDATE来对比不同厂商的PRICE。
 


------解决方案--------------------
SQL code


create table t1(docentry int,cardcode varchar(10),docdate date,docduedate date);
insert into t1 values
(1 ,'A001' ,'2012-01-01' ,'2012-03-25')
,(2 ,'A001' ,'2012-03-27' ,'2012-03-31')
,(3 ,'B001' ,'2012-05-01' ,'2012-05-07')
,(4 ,'C001' ,'2012-05-20' ,'2012-06-15');

create table t2(docentry int,itemcode varchar(100),price int);
insert into t2 values
(1,'ak-530', 10)
,(1, 'ak-cc', 8)
,(2, 'ak-530', 99)
,(3, 'mp-a52' ,7)
,(4, 'ak-530' ,25);

-- 假设这里只有三种类型
select 
itemcode
,sum(case when cardcode='A001' then price else 0 end) as A001
,max(case when cardcode='A001' then docdate else '' end) as A001docdate
,max(case when cardcode='A001' then docduedate else '' end) as A001docduedate
,sum(case when cardcode='B001' then price else 0 end) as B001
,max(case when cardcode='B001' then docdate else '' end) as B001docdate
,max(case when cardcode='B001' then docduedate else '' end) as B001docduedate
,sum(case when cardcode='C001' then price else 0 end) as C001
,max(case when cardcode='C001' then docdate else '' end) as C001docdate
,max(case when cardcode='C001' then docduedate else '' end) as C001docduedate
from t2 a join (select * from t1 x where not exists(select 1 from t1 where cardcode=x.cardcode and docdate>x.docdate)) b
    on a.docentry=b.docentry
group by itemcode

/*
itemcode     A001        A001docdate A001docduedate B001        B001docdate B001docduedate C001        C001docdate C001docduedate
------------ ----------- ----------- -------------- ----------- ----------- -------------- ----------- ----------- --------------
ak-530       99          2012-03-27  2012-03-31     0           1900-01-01  1900-01-01     25          2012-05-20  2012-06-15
mp-a52       0           1900-01-01  1900-01-01     7           2012-05-01  2012-05-07     0           1900-01-01  1900-01-01
*/

------解决方案--------------------
SQL code
if object_id('[tb1]') is not null drop table [tb1]
go
create table [tb1]([docentry] int,[cardcode] varchar(4),[docdate] datetime,[docduedate] datetime)
insert [tb1]
select 1,'A001','2012-01-01','2012-03-25' union all
select 2,'A001','2012-03-27','2012-03-31' union all
select 3,'B001','2012-05-01','2012-05-07' union all
select 4,'C001','2012-05-20','2012-06-15'
go
if object_id('[tb2]') is not null drop table [tb2]
go
create table [tb2]([docentry] int,[itemcode] varchar(6),[price] int)
insert [tb2]
select 1,'ak-530',10 union all
select 1,'ak-cc',8 union all
select 2,'ak-530',99 union all
select 3,'mp-a52',7 union all
select 4,'ak-530',25
go

declare @sql varchar(8000)
select @sql=isnull(@sql+',','')
  +'max(case when a.cardcode='''+cardcode+''' then a.docdate end) as [docdate'+cardcode+'],'
  +'max(case when a.cardcode='''+cardcode+''' then a.docduedate end) as [docduedate'+cardcode+'],'
  +'max(case when a.cardcode='''+cardcode+''' then b.price end) as ['+cardcode+']'
from
(select distinct cardcode from tb1) t

set @sql='select b.itemcode,'+@sql
  +' from tb1 a join tb2 b on a.docentry=b.docentry'
  +' where not exists(select 1 from tb1 where cardcode=a.cardcode and docdate>a.docdate)'
  +' group by b.itemcode'
exec (@sql)

/*