I want to use Pivot
to convert rows to columns.
I have three tables:
Student
table with columns StudentID
and StudentName
Subject
table with columns SubjectID
and SubjectName
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.