查询将某些行转置为列名

时间:2009-05-29 14:16:16

标签: sql sql-server pivot transpose

我有几张看起来像这样的桌子 表1

user_id   |  name
-------------------------   
x111      |   Smith, James
x112      |   Smith, Jane

等。

表2

id    |   code    |    date       |  incident_code    | user_id
-----------------------------------------------------------------
1     |    102008 |   10/20/2008  |    1              | x111
2     |    113008 |   11/30/2008  |    3              | x111
3     |    102008 |   10/20/2008  |    2              | x112
4     |    113008 |   11/30/2008  |    5              | x112 

我要展示的是这样的

user_id     |    user_name    |   INCIDENT IN OCT 2008   | INCIDENT IN NOV 2008
------------------------------------------------------------------------------ 
x111        |    Smith, John  |   1                      | 3
x112        |    Smith, Jane  |   2                      | 5

等。

incident_code将被位于另一个表中的事件的实际描述所取代,但我想我会先看看它是如何工作的。

某些列标题是静态的,而其他列标题则是根据日期创建的。 有谁知道我怎么能用sql server 2005做到这一点?一些例子会非常有用。

提前致谢

4 个答案:

答案 0 :(得分:2)

这是一个使用PIVOT:

生成并运行动态SQL的解决方案
DECLARE @pivot_list AS VARCHAR(MAX)

--
;
WITH    cols
          AS ( SELECT DISTINCT
                        'INCIDENT IN ' + LEFT(UPPER(CONVERT(VARCHAR, [date], 107)),
                                              3) + ' '
                        + SUBSTRING(UPPER(CONVERT(VARCHAR, [date], 107)), 9, 4) AS col
               FROM     so926209_2
             )
    SELECT  @pivot_list = COALESCE(@pivot_list + ', ', '') + '[' + col + ']'
    FROM    cols

--
DECLARE @template AS VARCHAR(MAX)
SET @template = 'WITH incidents AS (
SELECT  [user_id],
        incident_code,
        ''INCIDENT IN '' + LEFT(UPPER(CONVERT(VARCHAR, [date], 107)), 3)
        + '' '' + SUBSTRING(UPPER(CONVERT(VARCHAR, [date], 107)), 9, 4) AS col
FROM    so926209_2
)
,results AS (
SELECT * FROM incidents PIVOT (MAX(incident_code) FOR col IN ({@pivot_list})) AS pvt
)
SELECT results.[user_id]
    ,so926209_1.[name]
    ,{@select_list}
FROM results INNER JOIN so926209_1 ON so926209_1.[user_id] = results.[user_id]
'

DECLARE @sql AS VARCHAR(MAX)
SET @sql = REPLACE(REPLACE(@template, '{@pivot_list}', @pivot_list), '{@select_list}', @pivot_list)

--PRINT @sql
EXEC (@sql)

so926209_1so926209_2是您的表1和表2

请注意,如果同一个人一个月内发生多起事件,则您的示例不会显示您希望如何处理这些事件。此示例仅采用该月的最后一次事件。

答案 1 :(得分:0)

答案 2 :(得分:0)

这听起来像是一个报告任务。报告(通常从数据库角度称为OLAP,在线分析处理)往往与“传统”数据库访问OLTP(在线事务处理)的频率不同,因为它通常由跨越更长时期的大量数据聚合组成。时间很常见,您寻找的那种聚合。

使用Pivot作为Tetraneutron建议对于较小的数据集就足够了。但是,随着您需要报告的数据量的增长,您可能需要更高级的数据。 OLAP由SQL Server Analysis Services(SSAS)提供,可在2005年和2008年使用。使用SSAS,您可以创建多维数据存储库,直接从OLTP数据库或中间数据仓库数据库预先聚合数据。多维数据(通常称为多维数据集)提供了一种更快的方式来访问从数据透视表中获取的数据类型,而不会干扰OLTP数据库中标准事务处理的性能。

如果您需要报告的数据量不超过少量,我建议您查看SQL Server Analysis Services 2005,OLAP,Cubes和MDX(T-SQL的多维扩展)。有一个更大的学习用于设置OLAP多维数据集的曲线,但一旦设置好,如果您有重要的报告需求,那么拥有OLAP多维数据集的好处就会很大。

答案 3 :(得分:0)

这样的查询可以起作用:

select
    u.User_id,
    u.Name,
    Okt2008Sum = sum(case when i.date between 
        '2008-10-01' and '2008-11-01' then 1 else 0 end),
    Nov2008Sum = sum(case when i.date between 
        '2008-11-01' and '2008-12-01'then 1 else 0 end)
from #incidents i
inner join #users u on i.user_id = u.user_id
group by u.user_id, u.name

根据您的客户端以及运行频率,您可以生成此查询。在SQL中,这看起来像:

create table #months (
    MonthName varchar(25),
    StartDate datetime
)

insert into #months values ('Okt2008','2008-10-01')
insert into #months values ('Nov2008','2008-11-01')

declare @query varchar(8000)
select @query = 'select u.User_id, u.Name '

select @query = @query + ', ' + MonthName + 
    ' = sum(case when i.date between ''' + cast(StartDate as varchar) + 
    ''' and ''' + cast(dateadd(m,1,StartDate) as varchar) + 
    ''' then 1 else 0 end) '
from #Months

select @query = @query + '
    from #incidents i
    inner join #users u on i.user_id = u.user_id
    group by u.user_id, u.name'

exec (@query)