现有数据表如下:
客户名称 报告月份                   报告更新时间          是否正式提交
格力 2008-06-01 00:00:00.000 2008-09-08 00:00:00.000 1
格力 2008-07-01 00:00:00.000 2008-09-08 00:00:00.000 0
格力 2008-08-01 00:00:00.000 2008-09-08 00:00:00.000 1
格力 2008-09-01 00:00:00.000 2008-09-10 00:00:00.000 0
美的 2008-09-01 00:00:00.000 2008-09-10 00:00:00.000 0
科龙 2008-09-01 00:00:00.000 2008-09-10 00:00:00.000 1传入两参数,arg1(报告开始时间=2008-05),arg2(报告结束时间=2008-09)
希望得到表2所示的结果: 
月份 格力       科龙 美的
2008-05 NULL      NULL NULL
2008-06 2008-09-08   NULL NULL
2008-07 NULL      NULL NULL
2008-08 2008-09-08   NULL NULL
2008-09 NULL    2008-09-10 NULL要求:只有正式提交的数据才把更新时间取出,没有正式提交的或没有提交的,时间设为null,但要求保留表结构.
注意:数据表中并没有5月份的数据,但结果表中希望有5月份的表结构。

解决方案 »

  1.   


    /*
    标题:普通行列转换(version 2.0)
    作者:爱新觉罗.毓华(十八年风雨,守得冰山雪莲花开)
    时间:2008-03-09
    地点:广东深圳
    说明:普通行列转换(version 1.0)仅针对sql server 2000提供静态和动态写法,version 2.0增加sql server 2005的有关写法。问题:假设有张学生成绩表(tb)如下:
    姓名 课程 分数
    张三 语文 74
    张三 数学 83
    张三 物理 93
    李四 语文 74
    李四 数学 84
    李四 物理 94
    想变成(得到如下结果): 
    姓名 语文 数学 物理 
    ---- ---- ---- ----
    李四 74   84   94
    张三 74   83   93
    -------------------
    */create table tb(姓名 varchar(10) , 课程 varchar(10) , 分数 int)
    insert into tb values('张三' , '语文' , 74)
    insert into tb values('张三' , '数学' , 83)
    insert into tb values('张三' , '物理' , 93)
    insert into tb values('李四' , '语文' , 74)
    insert into tb values('李四' , '数学' , 84)
    insert into tb values('李四' , '物理' , 94)
    go--SQL SERVER 2000 静态SQL,指课程只有语文、数学、物理这三门课程。(以下同)
    select 姓名 as 姓名 ,
      max(case 课程 when '语文' then 分数 else 0 end) 语文,
      max(case 课程 when '数学' then 分数 else 0 end) 数学,
      max(case 课程 when '物理' then 分数 else 0 end) 物理
    from tb
    group by 姓名--SQL SERVER 2000 动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
    declare @sql varchar(8000)
    set @sql = 'select 姓名 '
    select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
    from (select distinct 课程 from tb) as a
    set @sql = @sql + ' from tb group by 姓名'
    exec(@sql) --SQL SERVER 2005 静态SQL。
    select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b--SQL SERVER 2005 动态SQL。
    declare @sql varchar(8000)
    select @sql = isnull(@sql + '],[' , '') + 课程 from tb group by 课程
    set @sql = '[' + @sql + ']'
    exec ('select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b')---------------------------------/*
    问题:在上述结果的基础上加平均分,总分,得到如下结果:
    姓名 语文 数学 物理 平均分 总分 
    ---- ---- ---- ---- ------ ----
    李四 74   84   94   84.00  252
    张三 74   83   93   83.33  250
    */--SQL SERVER 2000 静态SQL。
    select 姓名 姓名,
      max(case 课程 when '语文' then 分数 else 0 end) 语文,
      max(case 课程 when '数学' then 分数 else 0 end) 数学,
      max(case 课程 when '物理' then 分数 else 0 end) 物理,
      cast(avg(分数*1.0) as decimal(18,2)) 平均分,
      sum(分数) 总分
    from tb
    group by 姓名--SQL SERVER 2000 动态SQL。
    declare @sql varchar(8000)
    set @sql = 'select 姓名 '
    select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
    from (select distinct 课程 from tb) as a
    set @sql = @sql + ' , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名'
    exec(@sql) --SQL SERVER 2005 静态SQL。
    select m.* , n.平均分 , n.总分 from
    (select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b) m,
    (select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
    where m.姓名 = n.姓名--SQL SERVER 2005 动态SQL。
    declare @sql varchar(8000)
    select @sql = isnull(@sql + ',' , '') + 课程 from tb group by 课程
    exec ('select m.* , n.平均分 , n.总分 from
    (select * from (select * from tb) a pivot (max(分数) for 课程 in (' + @sql + ')) b) m , 
    (select 姓名 , cast(avg(分数*1.0) as decimal(18,2)) 平均分 , sum(分数) 总分 from tb group by 姓名) n
    where m.姓名 = n.姓名')drop table tb ------------------
    ------------------/*
    问题:如果上述两表互相换一下:即表结构和数据为:
    姓名 语文 数学 物理
    张三 74  83  93
    李四 74  84  94
    想变成(得到如下结果): 
    姓名 课程 分数 
    ---- ---- ----
    李四 语文 74
    李四 数学 84
    李四 物理 94
    张三 语文 74
    张三 数学 83
    张三 物理 93
    --------------
    */create table tb(姓名 varchar(10) , 语文 int , 数学 int , 物理 int)
    insert into tb values('张三',74,83,93)
    insert into tb values('李四',74,84,94)
    go--SQL SERVER 2000 静态SQL。
    select * from
    (
     select 姓名 , 课程 = '语文' , 分数 = 语文 from tb 
     union all
     select 姓名 , 课程 = '数学' , 分数 = 数学 from tb
     union all
     select 姓名 , 课程 = '物理' , 分数 = 物理 from tb
    ) t
    order by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 end--SQL SERVER 2000 动态SQL。
    --调用系统表动态生态。
    declare @sql varchar(8000)
    select @sql = isnull(@sql + ' union all ' , '' ) + ' select 姓名 , [课程] = ' + quotename(Name , '''') + ' , [分数] = ' + quotename(Name) + ' from tb'
    from syscolumns 
    where name! = N'姓名' and ID = object_id('tb') --表名tb,不包含列名为姓名的其它列
    order by colid asc
    exec(@sql + ' order by 姓名 ')--SQL SERVER 2005 动态SQL。
    select 姓名 , 课程 , 分数 from tb unpivot (分数 for 课程 in([语文] , [数学] , [物理])) t--SQL SERVER 2005 动态SQL,同SQL SERVER 2000 动态SQL。--------------------
    /*
    问题:在上述的结果上加个平均分,总分,得到如下结果:
    姓名 课程   分数
    ---- ------ ------
    李四 语文   74.00
    李四 数学   84.00
    李四 物理   94.00
    李四 平均分 84.00
    李四 总分   252.00
    张三 语文   74.00
    张三 数学   83.00
    张三 物理   93.00
    张三 平均分 83.33
    张三 总分   250.00
    ------------------
    */select * from
    (
     select 姓名 as 姓名 , 课程 = '语文' , 分数 = 语文 from tb 
     union all
     select 姓名 as 姓名 , 课程 = '数学' , 分数 = 数学 from tb
     union all
     select 姓名 as 姓名 , 课程 = '物理' , 分数 = 物理 from tb
     union all
     select 姓名 as 姓名 , 课程 = '平均分' , 分数 = cast((语文 + 数学 + 物理)*1.0/3 as decimal(18,2)) from tb
     union all
     select 姓名 as 姓名 , 课程 = '总分' , 分数 = 语文 + 数学 + 物理 from tb
    ) t
    order by 姓名 , case 课程 when '语文' then 1 when '数学' then 2 when '物理' then 3 when '平均分' then 4 when '总分' then 5 enddrop table tb
      

  2.   

    楼上基本有所有的需求:
    没有正式提交的或没有提交的,时间设为null, 用case when ,例如:
    select 姓名 姓名,
      max(case 课程 when '语文' then 分数 else 0 end) 语文,
      max(case 课程 when '数学' then 分数 else 0 end) 数学,
      max(case 课程 when '物理' then 分数 else 0 end) 物理,
      cast(avg(分数*1.0) as decimal(18,2)) 平均分,
      sum(分数) 总分
    from tb
    group by 姓名
      

  3.   


    -- 参数
    DECLARE
    @arg1 char(6),
    @arg2 char(6);
    SELECT
    @arg1 = '200805',
    @arg2 = '200809'

    -- 查询处理-- 月份构造
    CREATE TABLE #dt(
    月份 char(7),
    dt1 datetime,
    dt2 datetime
    )
    DECLARE
    @dt_begin datetime,
    @dt_end datetime,
    @dt datetime
    SELECT
    @dt_begin = @arg1 + '01',
    @dt_end = DATEADD(Month, 1, @arg2 + '01'),
    @dt = @dt_begin

    WHILE @dt < @dt_end
    BEGIN
    INSERT #dt
    VALUES(
    CONVERT(char(7), @dt, 120),
    @dt,
    DATEADD(Month, 1, @dt))
    SET @dt = DATEADD(Month, 1, @dt)
    END-- 动态客户名称
    DECLARE
    @s nvarchar(4000)
    SELECT
    @s = N''
    SELECT
    @s = @s + N',' + QUOTENAME(客户名称)
    + N'=MAX(CASE 客户名称 WHEN N' + QUOTENAME(客户名称, N'''')
    + N' THEN 报告更新时间 END)'
    FROM(
    SELECT DISTINCT
    客户名称
    FROM 数据表
    )A
    EXEC(N'
    SELECT
    月份' + @s + N'
    FROM(
    SELECT
    A.月份,
    B.客户名称, B.报告更新时间
    FROM #dt A
    LEFT JOIN 数据表 B
    ON A.dt1 >= B.报告月份
    AND A.dt2 < B.报告月份
    AND B.是否正式提交 = 1
    )A
    GROUP BY 月份
    ')
      

  4.   

    create table tb(客户名称 varchar(10),报告月份 datetime,报告更新时间 datetime, 是否正式提交 int)
    insert into tb values('格力' ,'2008-06-01 00:00:00.000' ,'2008-09-08 00:00:00.000' ,1 )
    insert into tb values('格力' ,'2008-07-01 00:00:00.000' ,'2008-09-08 00:00:00.000' ,0 )
    insert into tb values('格力' ,'2008-08-01 00:00:00.000' ,'2008-09-08 00:00:00.000' ,1 )
    insert into tb values('格力' ,'2008-09-01 00:00:00.000' ,'2008-09-10 00:00:00.000' ,0 )
    insert into tb values('美的' ,'2008-09-01 00:00:00.000' ,'2008-09-10 00:00:00.000' ,0 )
    insert into tb values('科龙' ,'2008-09-01 00:00:00.000' ,'2008-09-10 00:00:00.000' ,1 )
    go
    declare @dt1 as varchar(7)
    declare @dt2 as varchar(7)
    set @dt1 = '2008-05'
    set @dt2 = '2008-09'--临时表
    select top 8000 identity(int,0,1) as id into tmp from syscolumns a,syscolumns bselect m.yf , n.格力 , n.科龙 , n.美的 from
    (select convert(varchar(7),dateadd(mm,tmp.id,@dt1+'-01'),120) yf from tmp where dateadd(mm,tmp.id,@dt1+'-01') <= @dt2 + '-01') m
    left join
    (select convert(varchar(7),报告月份,120) yf ,
      max(case 客户名称 when '格力' then convert(varchar(10),报告更新时间,120) else null end) '格力',
      max(case 客户名称 when '科龙' then convert(varchar(10),报告更新时间,120) else null end) '科龙',
      max(case 客户名称 when '美的' then convert(varchar(10),报告更新时间,120) else null end) '美的'
    from tb where 是否正式提交 = 1 group by convert(varchar(7),报告月份,120) ) n
    on m.yf = n.yfdrop table tb , tmp/*
    yf      格力         科龙         美的         
    ------- ---------- ---------- ---------- 
    2008-05 NULL       NULL       NULL
    2008-06 2008-09-08 NULL       NULL
    2008-07 NULL       NULL       NULL
    2008-08 2008-09-08 NULL       NULL
    2008-09 NULL       2008-09-10 NULL(所影响的行数为 5 行)
    */
      

  5.   


    declare @sql varchar(8000)
    set @sql='' select @sql=@sql+',['+ClientName+']=max(case ClientName when '''+ClientName+''' then convert(varchar(10),ReportDate,120) else null end)'
    from 
    (
    select distinct ClientName from 
    Client
    ) table1 set @sql=
    'select convert(varchar(7),ReportMonth,120) as 月份'+@sql+' 
    from 
    (
    select ClientName,ReportMonth,ReportDate
    from MonthReport,Client
    where MonthReport.ClientID = Client.ClientID and ReportMonth>=''2008-05-01'' and ReportMonth <=''2008-09-01''
    ) a
    group by ReportMonth' exec(@sql)
    上面是在不考虑是否正式提交,不考虑5月份数据的情况下的代码。可以分两步帮小弟解决问题,
    1.只考虑正式提交的数据
    2.考虑5月份的数据望大家赐教
      

  6.   

    典型的列转行,3,9,10楼的回复很好,但太复杂本人觉得此语句并不难,现在关键是在楼主所取参数的这个表中的字段及数据如果参数表假设为 arg,数据如下:id     date0        date1      memo
    1    2008-05-01  2008-05-31  2008-05
    2    2008-06-01  2008-06-30  2008-06
    3    2008-07-01  2008-07-31  2008-07
    4    2008-08-01  2008-08-31  2008-08
    5    2008-09-01  2008-09-30  2008-09那么就可以这样写语句:
    select 月份=T.memo,格力=case G.是否正式提交 when 1 then isnull(G.报告更新时间,NULL) end,美的=case Y.是否正式提交 when 1 then isnull(Y.报告月份,NULL) end
    ,科龙=case K.是否正式提交 when 1 then isnull(K.报告月份,NULL) end
    from s_session T
     left join (select * from 报告表 where 客户名称='格力') as G on G.报告月份=T.date0
     left join (select * from 报告表 where 客户名称='美的') as Y on Y.报告月份=T.date0
     left join (select * from 报告表 where 客户名称='科龙') as K on Y.报告月份=T.date0
    where T.id>=1 and T.id<=5
      

  7.   

    不固定需要使用动态SQL语句.参照3楼的做法.
      

  8.   

    create table tb(姓名 varchar(10) , 课程 varchar(10) , 分数 int)
    insert into tb values('张三' , '语文' , 74)
    insert into tb values('张三' , '数学' , 83)
    insert into tb values('张三' , '物理' , 93)
    insert into tb values('李四' , '语文' , 74)
    insert into tb values('李四' , '数学' , 84)
    insert into tb values('李四' , '物理' , 94)
    go--SQL SERVER 2000 静态SQL,指课程只有语文、数学、物理这三门课程。(以下同)
    select 姓名 as 姓名 ,
      max(case 课程 when '语文' then 分数 else 0 end) 语文,
      max(case 课程 when '数学' then 分数 else 0 end) 数学,
      max(case 课程 when '物理' then 分数 else 0 end) 物理
    from tb
    group by 姓名--SQL SERVER 2000 动态SQL,指课程不止语文、数学、物理这三门课程。(以下同)
    declare @sql varchar(8000)
    set @sql = 'select 姓名 '
    select @sql = @sql + ' , max(case 课程 when ''' + 课程 + ''' then 分数 else 0 end) [' + 课程 + ']'
    from (select distinct 课程 from tb) as a
    set @sql = @sql + ' from tb group by 姓名'
    exec(@sql) --SQL SERVER 2005 静态SQL。
    select * from (select * from tb) a pivot (max(分数) for 课程 in (语文,数学,物理)) b
      

  9.   


    -- 参数
    DECLARE
        @arg1 char(6),
        @arg2 char(6);
    SELECT
        @arg1 = '200805',
        @arg2 = '200809' CREATE TABLE #dt(
    月份 char(7)
    )
    DECLARE
    @dt_begin datetime,
    @dt_end datetime,
    @dt datetime        
    SELECT
    @dt_begin = @arg1 + '01',
    @dt_end = DATEADD(Month, 1, @arg2 + '01'),
    @dt = @dt_begin
        
    WHILE @dt < @dt_end
    BEGIN
    INSERT #dt
    VALUES(
    CONVERT(char(7), @dt, 120))
    SET @dt = DATEADD(Month, 1, @dt)
    END declare @sql varchar(8000)
    set @sql='' declare @columns varchar(1000)
    set @columns='' select @sql=@sql+',['+ClientName+']=max(case ClientName when '''+ClientName+''' then convert(varchar(10),ReportDate,120) else null end)',
       @columns = @columns +','+ClientName
    from 
    (
    select distinct ClientName from 
    Client
    ) table1 set @sql=
    'select convert(varchar(7),ReportMonth,120) as 月份'+@sql+' 
    from 
    (
    select ClientName,ReportMonth,ReportDate
    from MonthReport,Client
    where MonthReport.ClientID = Client.ClientID and IsSubmited = 1 and ReportMonth>=''2008-05-01'' and ReportMonth <=''2008-09-01''
    ) a
    group by ReportMonth' set @sql = 
    ' select #dt.月份'+@columns+' from #dt left join ('+@sql+')n on #dt.月份 = n.月份' exec(@sql) drop table #dt
    参考了9楼和10楼两位强人的代码,修改如上,可以解决我的问题了。再次感谢