简体   繁体   中英

Convert Rows to Column In SQL Server 2008

I want to use Pivot to convert rows to columns.

I have three tables:

  1. Student table with columns StudentID and StudentName
  2. Subject table with columns SubjectID and SubjectName
  3. Student Subject table with columns StudentSubjectID , StudentID , SubjectID and Date

Now I wrote a query to get data from the above tables

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

Now I will make a monthly report to display Student Subject per month and output should be

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             -                 -                  -                                                -

How can I do this?

Thank you

I guess the script will require too complex dynamic coding, I had just created a schema but will take too much effort to convert for a complete dynamic SQL script

;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

I hope it helps somehow, But I guess after SQL concatenation of subjectname fields, the below query can be solved by a dynamic sql pivot

在此处输入图片说明

Please check following 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)

Here is my output

在此处输入图片说明

To summarize the query, first of all I need the current month's dates as column names. I used the calendar function module GetFullMonth at given reference. I just changed the return "datetime" column to "date" data type.

As I noted in my previous code sample, I used SQL concatenation with FOR XML PATH method.

One last reference I'ld like to share with you. I used date to string conversion in the PivotColumnHeaders section of the dynamic query where I define the additional pivot columns. I used the conversion parameter as 23. You can check for a full list of datetime format parameter at given reference.

I hope these helps you for the solution,

If you want to date column contains only what has your table, then you have to use this query. 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)

   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)

--partial column--

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    -   -   -   -   -   -   -   -

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM