Intro and Problem
In my example i have teachers, students and courses.I would like to have an overview which course is teached by whom in which rooms and all the studends in this course. I have the basic setup runnig (with some handcoded statements). But until now i had no luck to prepare the correct STUFF statement:
- Prepare
@colsStudents
so that i can put the name in the column header and remove the need to mess with the ids (adding 100) to avoid a conflict between rooms.id and students.id - Prepare
@colsRooms
so that i do not have to hardocde the roomnames - Putting i all together by using
EXEC sp_executesql @sql;
You can find all sql-statements to create this schema and the data at the end.
Wanted Result Overview Courses,
I would like pivot the columns RoomName
and StudentName
and use the column values as the new column names. All SQL-Statements to create tables and data are at the end.
Id | Course | Teacher | A3 | E7 | Penny | Cooper | Koothrap. | Amy
---+--------+---------+----+----+-------+--------+-----------+-----+
1 | C# 1 | Marc G. | | 1 | 1 | | |
2 | C# 2 | Sam S. | | 1 | 1 | | 1 |
3 | C# 3 | John S. | 1 | | | 1 | |
4 | C# 3 | Reed C. | | 1 | | | 1 |
5 | SQL 1 | Marc G. | 1 | | | | |
6 | SQL 2 | Marc G. | 1 | | | | |
7 | SQL 3 | Marc G. | | 1 | | 1 | | 1
8 | SQL 3 | Gbn | 1 | | | | 1 |
What i have so far
With PivotData as (
Select cd.Id, c.CourseName as Course, t.TeacherName as Teacher
,r.Id as RoomId, r.RoomName as RoomName
,100 + s.Id as StudentId, s.StudentName as Student
FROM CourseDetails cd
Left JOIN Courses c ON cd.CourseId = c.Id
Left JOIN Teachers t ON cd.TeacherId = t.Id
Left JOIN CourseMember cm ON cd.Id = cm.CourseDetailsId
Left JOIN Students s ON cm.StudentId = s.Id
Left JOIN Rooms r ON cd.RoomId = r.Id
)
Select Course, Teacher
, [1] as A3, [2] as E7 -- RoomColumns
, [101] as Koothrappali, [102] as Cooper, [103] as Penny, [104] as Amy -- StudentColumns
FROM (
Select Course, Teacher, RoomName, RoomId,Student, StudentId
From PivotData) src
PIVOT( Max(RoomName) FOR RoomId IN ([1],[2])) as P1
PIVOT( Count(Student) FOR StudentId IN ([101],[102],[103],[104]) ) as P2
What is missing
The above statement is prepared by hand. Since i do not know the Rooms or Students in advance i need to create the Pivot Statement for the Columns Rooms and Students dynamically. On SO are plenty of examples how to do it. The normal way to do that is to use STUFF:
DECLARE @colsStudents AS NVARCHAR(MAX);
SET @colsStudents = STUFF(
(SELECT N',' + QUOTENAME(y) AS [text()] FROM
(SELECT DISTINCT 100 + Id AS y FROM dbo.Students) AS Y
ORDER BY y
FOR XML PATH('')
),1
,1
,N'');
Select @colsStudents
This returns [101],[102],[103],[104]
for the Student Ids. I added 100 to each id to avoid conflicts between the students.id and teh rooms.id column.
As mentioned in the intro i need to dynamically create something like this
[1] as RoomName_1, [2] as RoomName_1 -- RoomColumns
[1] as StudentName1, [2] as StudentName2, ... ,[4] as Amy -- StudentColumns
But all my tries with the stuff statement failed.
All SQL Statements to create the tables and data
CREATE TABLE [dbo].[Teachers](
[Id] [int] IDENTITY(1,1) NOT NULL,
[TeacherName] [nvarchar](120) NULL,
CONSTRAINT PK_Teachers PRIMARY KEY CLUSTERED (Id))
CREATE TABLE [dbo].[Students](
[Id] [int] IDENTITY(1,1) NOT NULL,
[StudentName] [nvarchar](120) NULL,
CONSTRAINT PK_Students PRIMARY KEY CLUSTERED (Id))
CREATE TABLE [dbo].[Courses](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CourseName] [nvarchar](120) NULL,
CONSTRAINT PK_Courses PRIMARY KEY CLUSTERED (Id))
CREATE TABLE [dbo].[Rooms](
[Id] [int] IDENTITY(1,1) NOT NULL,
[RoomName] [nchar](120) NULL,
CONSTRAINT PK_Rooms PRIMARY KEY CLUSTERED (Id))
CREATE TABLE [dbo].[CourseDetails](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CourseId] [int] NOT NULL,
[TeacherId] [int] NOT NULL,
[RoomId] [int] NOT NULL,
CONSTRAINT PK_CourseDetails PRIMARY KEY CLUSTERED (Id),
CONSTRAINT FK_CourseDetails_Teachers_Id FOREIGN Key (TeacherId)
REFERENCES dbo.Teachers (Id),
CONSTRAINT FK_CourseDetails_Courses_Id FOREIGN Key (CourseId)
REFERENCES dbo.Courses (Id),
CONSTRAINT FK_CourseDetails_Rooms_Id FOREIGN Key (RoomId)
REFERENCES dbo.Rooms (Id)
)
CREATE TABLE [dbo].[CourseMember](
[Id] [int] IDENTITY(1,1) NOT NULL,
[CourseDetailsId] [int] NOT NULL,
[StudentId] [int] NOT NULL,
CONSTRAINT PK_CourseMember PRIMARY KEY CLUSTERED (Id),
CONSTRAINT FK_CourseMember_CourseDetails_Id FOREIGN Key (CourseDetailsId)
REFERENCES dbo.CourseDetails (Id),
CONSTRAINT FK_CourseMember_Students_Id FOREIGN Key (StudentId)
REFERENCES dbo.Students (Id)
)
INSERT INTO dbo.Courses (CourseName)
VALUES ('SQL 1 - Basics'),
('SQL 2 - Intermediate'),
('SQL 3 - Advanced'),
('C# 1 - Basics'),
('C# 2 - Intermediate'),
('C# 3 - Advanced')
INSERT INTO dbo.Students (StudentName)
VALUES
('Koothrappali'),
('Cooper'),
('Penny'),
('Amy')
INSERT INTO dbo.Teachers (TeacherName)
VALUES
('gbn '),
('Sam S.'),
('Marc G.'),
('Reed C.'),
('John S.')
INSERT INTO dbo.Rooms (RoomName)
VALUES ('A3'), ('E7')
INSERT [dbo].[CourseDetails] (CourseId, TeacherId, RoomId)
VALUES (4, 3, 2),(5, 2, 2),
(6, 5, 1),(6, 4, 2),
(1,3,1),(2,3,1),(3,3,2),
(3,1,1)
INSERT [dbo].[CourseMember] (CourseDetailsId, StudentId)
VALUES (1,3),(2,3),(2,1),(3,2),(4,1),(7,2),(7,4),(8,1)