在SQL Server 2008中将行转换为列

时间:2017-01-04 05:46:49

标签: sql sql-server

我想使用Pivot将行转换为列。

我有三张桌子:

  1. Student表格,其中包含StudentID列和StudentName
  2. Subject表格,其中包含SubjectID列和SubjectName
  3. Student Subject表包含StudentSubjectIDStudentIDSubjectIDDate
  4. 现在我写了一个查询来从上面的表中获取数据

    StudentID   StudentName   SubjectID   SubjectName  DateTime  
    -----------------------------------------------------------    
    1           Yasser            1       Math         1/1/2017
    1           Yasser            1       English      1/1/2017
    1           Yasser            1       Math         3/1/2017
    1           Mark              1       Math         1/1/2017
    1           John              1       Math         6/1/2017
    

    现在我将每月制作一份报告,每月显示学生科目,输出应为

    Student/Days    1/1/2017      2/1/2017     3/1/2017    4/1/2017  ......................................... 30/1/2017    (All days for month)
    
    Yasser                 Math             -                 Math           -                                                -
    
                               English             -               -                 -                                                -
    
    Mark                   Math             -                 -                  -                                                -
    

    我该怎么做?

    谢谢

4 个答案:

答案 0 :(得分:0)

我猜这个脚本需要太复杂的动态编码, 我刚刚创建了一个模式,但转换为完整的动态SQL脚本需要花费太多精力

;with cte as (
select distinct StudentName, SubjectName, [DateTime] from studentCTE
), cte2 as (
select 
    StudentName,
    case when [DateTime] = '2017-01-01' then SubjectName else null end as '2017-01-01',
    case when [DateTime] = '2017-03-01' then SubjectName else null end as '2017-03-01',
    case when [DateTime] = '2017-06-01' then SubjectName else null end as '2017-06-01'
from cte
)
SELECT distinct
  StudentName,
  STUFF(
    (
    SELECT
      ',' + [2017-01-01]
    FROM cte2 C
    where c.StudentName = cte2.StudentName
    FOR XML PATH('')
    ), 1, 1, ''
  ) As '2017-01-01',
  STUFF(
    (
    SELECT
      ',' + [2017-03-01]
    FROM cte2 C
    where c.StudentName = cte2.StudentName
    FOR XML PATH('')
    ), 1, 1, ''
  ) As '2017-03-01',
  STUFF(
    (
    SELECT
      ',' + [2017-06-01]
    FROM cte2 C
    where c.StudentName = cte2.StudentName
    FOR XML PATH('')
    ), 1, 1, ''
  ) As '2017-06-01'
from cte2

我希望它有所帮助, 但我想在SQL concatenation个主题名字段之后,下面的查询可以通过动态sql pivot来解决

enter image description here

答案 1 :(得分:0)

请检查dynamic SQL pivot query

DECLARE @PivotColumnHeaders VARCHAR(MAX)
SELECT @PivotColumnHeaders =
  COALESCE(
    @PivotColumnHeaders + ',[' + convert(nvarchar(20),date,23) + ']',
    '[' + convert(nvarchar(20),date,23) + ']'
  )
FROM dbo.GetFullMonth(getdate())


DECLARE @PivotTableSQL NVARCHAR(MAX)
SET @PivotTableSQL = N'
  SELECT *
  FROM (
                select distinct StudentName,
                  STUFF(
                    (
                    SELECT
                      '','' + SubjectName
                    FROM studentCTE C
                    where c.StudentName = studentCTE.StudentName
                    and c.DateTime = studentCTE.DateTime
                    FOR XML PATH('''')
                    ), 1, 1, ''''
                  ) As Subjects
                  , [DateTime]
                from studentCTE
  ) AS PivotData
  PIVOT (
    MAX(Subjects)
    FOR [DateTime] IN (
      ' + @PivotColumnHeaders + '
    )
  ) AS PivotTable
'
EXECUTE(@PivotTableSQL)

这是我的输出

enter image description here

要总结查询,首先我需要将当前月份的日期作为列名。我在给定的引用中使用了calendar function module GetFullMonth。我刚刚更改了返回" datetime"列到"日期"数据类型。

正如我在之前的代码示例中所提到的,我使用SQL串联和FOR XML PATH方法。

最后一个参考资料我想与您分享。我在动态查询的PivotColumnHeaders部分中使用date来进行字符串转换,我在其中定义了其他数据透视表列。我使用转换参数为23。 您可以在给定参考位置检查datetime format parameter的完整列表。

我希望这些可以帮助您解决问题,

答案 2 :(得分:0)

如果您希望日期列仅包含您的表的内容,则必须使用此查询。 DECLARE @DYNQRY AS VARCHAR(MAX) ,@COL AS VARCHAR(MAX) SELECT @COL= ISNULL(@COL + ',','') + QUOTENAME(DATE) FROM (SELECT DISTINCT DATE FROM STUDENTSUBJECT) AS DATE SET @DYNQRY ='SELECT STUDENTNAME, ' + @COL + ' FROM (SELECT A.STUDENTID,STUDENTNAME,SUBJECTNAME,DATE FROM STUDENT A,SUBJECT B,STUDENTSUBJECT C WHERE A.STUDENTID=C.STUDENTID AND B.SUBJECTID=C.SUBJECTID )A PIVOT( MAX(SUBJECTNAME) FOR DATE IN (' + @COL + ') ) AS PVTTABLE' EXEC (@DYNQRY)

答案 3 :(得分:0)

   CREATE TABLE #tt(StudentID INT,StudentName VARCHAR(200),SubjectID INT,SubjectName VARCHAR(200),[DateTime]DATETIME)
    INSERT INTO #tt  
    SELECT 1,'Yasser',1,'Math','01/01/2017' UNION
    SELECT 1,'Yasser',1,'English','01/01/2017' UNION
    SELECT 1,'Yasser',1,'Math','01/03/2017' UNION
    SELECT 1,'Mark',1,'Math','01/01/2017' UNION
    SELECT 1,'John',1,'Math','01/06/2017'

            DECLARE @col1 VARCHAR(max),@col2 VARCHAR(max),@sql VARCHAR(max)
    SELECT @col1=ISNULL(@col1+',','')+ t.d
          ,@col2=ISNULL(@col2+',','')+'ISNULL('+ t.d  +',''-'') AS '+t.d
     FROM #tt 
    INNER JOIN master.dbo.spt_values AS sv ON sv.type='P' AND sv.number BETWEEN 0 AND 30
    CROSS APPLY(VALUES('['+CONVERT(VARCHAR,DATEADD(dd,sv.number,DATEADD(MONTH, MONTH([DateTime])-1,DATEADD(YEAR,YEAR([DateTime])-1900,0))),110)+']')) t(d)
    WHERE MONTH(DATEADD(dd,sv.number,DATEADD(MONTH, MONTH([DateTime])-1,DATEADD(YEAR,YEAR([DateTime])-1900,0))))= MONTH([DateTime])
    GROUP BY MONTH([DateTime]),YEAR([DateTime]),sv.number,t.d
    PRINT @col2
    SET @sql='
    SELECT StudentID,StudentName,'+@col2+'  FROM #tt
    PIVOT(max(SubjectName) FOR [DateTime] IN ('+@col1+')) p'
    EXEC (@sql)

- 部分栏目 -

StudentID   StudentName 01-01-2017  01-02-2017  01-03-2017  01-04-2017  01-05-2017  01-06-2017  01-07-2017  01-08-2017  01-09-2017  01-10-2017  01-11-2017
1   John    -   -   -   -   -   Math    -   -   -   -   -
1   Mark    Math    -   -   -   -   -   -   -   -   -   -
1   Yasser  Math    -   Math    -   -   -   -   -   -   -   -