n to n relationship how to obtain a result in one row - sql

so I have an employee that can work in many companies so I have an n to n relationship, how can I obtain the companies that one employee works in, in just one row with sql?
example
table - employee
Employeeid employeename
1 mike
table company
companyId CompanyName
1 cocacola
2 nokia
3 intel
table employeeCompany
id employeeid companyid
1 1 1
2 1 2
3 1 3
I thought with this but canĀ“t
select Employeeid , companyid
from employeeCompany
where employeeid = 1
group by Employeeid , companyid

Easiest way to do it in Sql Server is by use of FOR XML PATH. The cryptic part .value('text()[1]','nvarchar(max)') handles special xml characters.
select employee.*, companies.*
from Employee
OUTER APPLY
(
select stuff ((SELECT ', ' + Company.CompanyName
FROM EmployeeCompany
INNER JOIN Company
ON EmployeeCompany.CompanyId = Company.CompanyID
WHERE EmployeeCompany.employeeid = Employee.EmployeeID
ORDER BY Company.CompanyName
FOR XML PATH(''),TYPE).value('text()[1]','nvarchar(max)')
, 1, 2, '') Companies
) companies
See demo at Sql Fiddle.

It sounds like you want something that is similar to mySQL's Group_Concat in SQL Server?
If you are looking for a way to do this so that each companyid is in a separate column, then that would only be possible with some difficulty using dynamic SQL. At which time it might be easier to just return this to an application and let it handle what it needs within its own logic?
BTW, the dynamic SQL logic would go something like this in case you were wondering...notice how nasty it is...thus why I would suggest against it.
select #highestCount = max(count(*))
from employeeCompany
group by Employeeid
declare createtemptable varchar(max), #filltableselect varchar(max), #filltablejoin varchar(max)
declare #currentCount int
set #currentCount = 0
set #createtemptable = 'CREATE TABLE #Temp (EmployeeID INT'
set #filltableselect = 'INSERT INTO #Temp SELECT EmployeeCompany0.EmployeeID, EmployeeCompany0.CompanyID'
set #filltablejoin = 'FROM EmployeeCompany AS EmployeeCompany0'
while(#currentCount < #highestCount)
begin
set #createtemptable = #createtemptable + ', CompanyID'
+ CAST(#currentCount AS VARCHAR(2)) + ' INT'
if(#currentCount > 0)
begin
set #filltableselect = #filltableselect + ', EmployeeCompany'
+ CAST(#currentCount AS VARCHAR(2)) + '.CompanyId'
set #filltablejoin = #filltablejoin
+ 'LEFT JOIN EmployeeCompany AS EmployeeCompany'
+ CAST(#currentCount AS VARCHAR(2))
+ ' ON EmployeeCompany0.EmployeeID = EmployeeCompany'
+ CAST(#currentCount AS VARCHAR(2)) + '.EmployeeID'
end
set #currentCount = #currentCount + 1
end
set #createtemptable = #createtemptable + ')'
--This next line can be whatever you need it to be
set #filltablejoin = #filltablejoin + 'WHERE employeeCompany0.EmployeeID = 1'
exec #createtemptable
exec #filltableselect + #filltablejoin

Related

Select column name dynamically based on rows from another table in SQL server

I need to make below situation. I need a.DATE_TIME field to find right column name in parentheses. Because there are columns for each days and I need calculate day from SHIFT_TABLE. Column names start with 'TPR' plus day like TPR13
DECLARE #SQLText NVARCHAR(MAX) = ''
SELECT #SQLText += 'SELECT (SELECT '
SELECT #SQLText += ( 'TPR' + Convert(varchar,DATEPART(day,a.DATE_TIME) )
) +
' from SHIFT_TABLE as s Where s.id = a.id ) from MAIN_TABLE as a where a.id=''1'' and a.ay=''12'' and a.yil=''2018'' '
print #SQLText
I take error message: The multi-part identifier "a.DATE_TIME" could not be bound.
SHIFT_TABLE occurs id and TPR01,TPR02,...TPR31 columns
MAIN_TABLE occurs id, ay, yil and DATE_TIME columns
I have to calculate day from a.DATE_TIME.
As a result I try to reach like this, SELECT (SELECT TPR13 from SHIFT_TABLE as s Where s.id = a.id ) from MAIN_TABLE as a where a.id='1' and a.ay='12' and a.yil='2018'
How can I solve it? Many Thanks,
DECLARE #SQLText NVARCHAR(MAX) = ''
SELECT #SQLText += 'SELECT (SELECT '
SELECT #SQLText += ( 'TPR' + Convert(varchar,DATEPART(day,a.DATE_TIME) )
) +
' from SHIFT_TABLE as s Where s.id = a.id ) from MAIN_TABLE as a where a.id=''1'' and a.ay=''12'' and a.yil=''2018'' '
FROM [YourTableWhere_DATE_TIME_Exists] AS a
print #SQLText

Invalid length parameter passed to the LEFT or SUBSTRING function in my query. It runs perfect id DTS 2008 but gives this error in SSIS 2014

DECLARE #ColumnTotal INT,
#HTProcOfficeColumnNames NVARCHAR(4000),
#TBLColumnNames NVARCHAR(4000),
#query NVARCHAR(4000),
#subqueryInsert NVARCHAR(4000),
#subqueryValues NVARCHAR(4000)
SELECT #ColumnTotal = Count(*)
FROM (SELECT htprocoffice
FROM table
WHERE COLUMN NOT LIKE '% - CO'
GROUP BY COLUMN) T
SELECT #HTProcOfficeColumnNames = COALESCE(#HTProcOfficeColumnNames
+ ',[' + htprocoffice + ']', '[' + htprocoffice + ']')
FROM (SELECT htprocoffice
FROM table
WHERE COLUMN NOT LIKE '% - CO'
GROUP BY COLUMN) T
ORDER BY COLUMN
SELECT #TBLColumnNames = COALESCE(#TBLColumnNames + ',' + NAME, NAME)
FROM table
WHERE id IN (SELECT id
FROM table
WHERE type = 'U'
AND NAME = 'TableName')
AND NAME LIKE 'HTOffice%'
ORDER BY NAME
Is there any error in the below code?
set #subqueryInsert = substring(#TBLColumnNames,1,#ColumnTotal*11-1) --The error occurs here but not sure though.
set #subqueryInsert = 'INSERT INTO Table
(RunDate,OrderBy,Period,IConOffice,IConOfficeType,'+ #subqueryInsert+')'
set #subqueryValues =
replace(replace(#HTProcOfficeColumnNames,'[',''''), ']','''')

Pivoting SQL Server result set

if I have a result returned as follows:
pkTestInstanceID Percent1 Count1 Percent2 Count2
1 25 1 75 3
2 50 2 50 2
Is there a way so it pivots in such format:
pkTestInstanceID Percent Count
1 25 1
1 75 3
2 50 2
2 50 2
Sorry if this question is totally misguided. I'm not super clear on the pivoting process. Thanks for any help.
EDIT I should probably have noted that the Percent1, Count1, Percent2 etc columns are created based off of another column (stackposition). So if stackposition has 4 rows then the percent and count will go up to percent4 count4. Is a pivot or union still possible without the knowledge of the exact number of percent and count columns in the result set.
EDIT 2: It gets a bit more complicated now...
I now realize that I have to include another item in my select statement (fkBandID). For each bandID there is a stackposition as stated above, so for bandID 96 the stackposition is 4, for 97 the stackposition is 3, for 98 the stackposition is 2 etc. so I want the result set to look as follows:
fkBandID pkTestInstanceID Band_Percent Band_Count StackPosition (not included but there for for visual example)
96 265 2 1 4
97 265 4 2 3
98 265 34 17 2
99 265 59 29 1
Here is what the creation of my second query looks like after the initial result set is brought back and with the bandID being selected including the new bandID. This is from Pradeep's answer.
http://gyazo.com/091ece1a4a1334c0f2546bccb8a6b8da
This is what the result set looks like, so as you can see there are 4 rows being created for each bandID. Is there anyway to fix this and make it look as I displayed above in the cross apply that Pradeep helped me with? Or any other solution?
http://gyazo.com/cd19634a1201362ac3aa4546f15373c9
Sorry I'm super nooby with SQL. Let me know if more info is needed.
EDIT 3
(N'DECLARE #strYearIds nvarchar(100)
SET #strYearIds = ''' + #strYearIds + N'''
DECLARE #strDemoCodeIds nvarchar(100)
SET #strDemoCodeIds = ''' + #strDemoCodeIds + N'''
DECLARE #intRosterSetId int
SET #intRosterSetId = ' + CONVERT(nvarchar, #intRosterSetId) + N'
DECLARE #intSchoolId int
SET #intSchoolId = ' + CONVERT(nvarchar, #intSchoolId) + N'
DECLARE #intTeachId int
SET #intTeachId = ' + CONVERT(nvarchar, #intTeachId) + N'
DECLARE #intGradeId int
SET #intGradeId = ' + CONVERT(nvarchar, #intGradeId) + N'
DECLARE #intDeptId int
SET #intDeptId = ' + CONVERT(nvarchar, #intDeptId) + N'
DECLARE #intCourseId int
SET #intCourseId = ' + CONVERT(nvarchar, #intCourseId) + N'
DECLARE #intPeriodId int
SET #intPeriodId = ' + CONVERT(nvarchar, #intPeriodId) + N'
DECLARE #strTestInstId nvarchar(100)
SET #strTestInstId = ''' + #strTestInstId + N'''
DECLARE #intTestTypeId int
SET #intTestTypeId = ' + CONVERT(nvarchar, #intTestTypeId) + N'
DECLARE #strSubIds nvarchar(100)
SET #strSubIds = ''' + #strSubIds + N'''
DECLARE #bitIsStrand bit
SET #bitIsStrand = ' + CONVERT(nvarchar, #bitIsStrand) + N'
DECLARE #intPerfLevelReportId int
SET #intPerfLevelReportId = ' + CONVERT(nvarchar, #intPerfLevelReportId) +
N' DECLARE #tempTests TABLE (id int)
INSERT INTO #tempTests
exec SPGetStudentTests_Local_MTI #strDemoCodeIds, #strYearIds, #intSchoolId, #intTeachId, #intGradeId,
#intRosterSetId, #intPeriodId, #intDeptId, #intCourseId, #strTestInstId, #intTestTypeId
DECLARE #tempSubs TABLE (id int)
IF #bitIsStrand = 1
BEGIN
INSERT INTO #tempSubs
SELECT pkTestSubjectID FROM MM_Test_Subjects WHERE fkCSTStrandID /*= #intSubID*/ IN (SELECT number FROM itot(#strSubIds, N'','')) AND fkTestTypeID = #intTestTypeId
END
ELSE
BEGIN
INSERT INTO #tempSubs
SELECT number FROM itot(#strSubIds, N'','')--VALUES (#intSubId)
END
SELECT bands.pkPerformanceLevelReportBandID AS ''fkBandID'', TestInstances.pkTestInstanceID AS ''TestInstanceID'', StudentScores_Subject.fkTest_SubjectID AS ''TestSubjectID'', '
+ #cols +
N'INTO ##tempTable FROM StudentScores_Subject
INNER JOIN StudentTests ON StudentScores_Subject.fkStudentTestID = StudentTests.pkStudentTestID
INNER JOIN TestInstances ON TestInstances.pkTestInstanceID = StudentTests.fkTestInstanceID
INNER JOIN CAHSEE_TestPeriods ON CAHSEE_TestPeriods.pkTestPeriodID = TestInstances.fkTestPeriodID
INNER JOIN PerformanceLevelReportBands bands ON bands.fkPerformanceLevelReportID = #intPerfLevelReportId
LEFT JOIN MMARS_Web_TestInfo_California.dbo.PerfLevelReportBandCutScores cutScores ON cutScores.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
AND cutScores.fkGradeID = #intGradeId
AND cutScores.fkTestSubjectID IN (SELECT id FROM #tempSubs)
INNER JOIN PerfLevelReportBandComponents bandComponents ON bandComponents.fkPerformanceLevelReportBandID = bands.pkPerformanceLevelReportBandID
AND((bandComponents.ScoreValue = StudentScores_Subject.ScoreValue) OR
((CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN bandComponents.minScore and bandComponents.maxScore)
OR
(CAST(StudentScores_Subject.ScoreValue AS INT) BETWEEN cutScores.minScore and cutScores.maxScore))
)
RIGHT JOIN MM_SchoolYears ON MM_SchoolYears.pkSchoolYearID = TestInstances.fkSchoolYearID
WHERE MM_SchoolYears.pkSchoolYearID IN (SELECT number FROM itot(#strYearIds, N'',''))
AND bands.fkPerformanceLevelReportID = #intPerfLevelReportId
AND StudentScores_Subject.fkStudentTestID IN (SELECT id FROM #tempTests)
AND StudentScores_Subject.fkScoreTypeID = bandComponents.fkScoreTypeID
AND StudentScores_Subject.fkTest_SubjectID IN (SELECT id FROM #tempSubs)
--AND((bandComponents.ScoreValue = StudentScores_Subject.ScoreValue) OR
--(StudentScores_Subject.ScoreValue BETWEEN bandComponents.minScore and bandComponents.maxScore) OR
--(StudentScores_Subject.ScoreValue BETWEEN cutScores.minScore and cutScores.maxScore))
GROUP BY bands.pkPerformanceLevelReportBandID, TestInstances.pkTestInstanceID, StudentScores_Subject.fkTest_SubjectID
ORDER BY bands.pkPerformanceLevelReportBandID, TestInstances.pkTestInstanceID, StudentScores_Subject.fkTest_SubjectID')
The #cols variable is as follows:
DECLARE #cols NVARCHAR(MAX)
SELECT #cols = STUFF(( SELECT DISTINCT TOP 100 PERCENT ', SUM(CASE WHEN bands.StackPosition = ''' + STR(b.StackPosition, 1) + ''' THEN 1 ELSE 0 END) * 100.0/ CASE WHEN COUNT(pkStudentScoreID) = 0 THEN 1 ELSE COUNT(pkStudentScoreID) END AS ''Percent_' + STR(b.StackPosition, 1) + ''', SUM(CASE WHEN bands.StackPosition = ''' + STR(b.StackPosition, 1) + ''' THEN 1 ELSE 0 END) AS ''Count_' + STR(b.StackPosition, 1) + ''''
FROM PerformanceLevelReportBands AS b
WHERE b.fkPerformanceLevelReportID = #intPerfLevelReportId
ORDER BY ', SUM(CASE WHEN bands.StackPosition = ''' + STR(b.StackPosition, 1) + ''' THEN 1 ELSE 0 END) * 100.0/ CASE WHEN COUNT(pkStudentScoreID) = 0 THEN 1 ELSE COUNT(pkStudentScoreID) END AS ''Percent_' + STR(b.StackPosition, 1) + ''', SUM(CASE WHEN bands.StackPosition = ''' + STR(b.StackPosition, 1) + ''' THEN 1 ELSE 0 END) AS ''Count_' + STR(b.StackPosition, 1) + ''''
FOR XML PATH('')
), 1, 2, '')
what you are looking for is Unpivot not pivot
CREATE TABLE #piv
(
pkTestInstanceID INT,
Percent1 INT,
Count1 INT,
Percent2 INT,
Count2 INT
)
INSERT INTO #piv
VALUES ( 1,25,1,75,3),
(2,50,2,50,2)
SELECT pkTestInstanceID,
[percent],
[count]
FROM #piv AS p
CROSS APPLY ( VALUES (Percent1,Count1),
(Percent2,Count2))
AS x([percent], [count]);
If you want this to work dynamically then below code should help you.
For example i have kept no. of stackposition rows as 2 u can change it and check
DECLARE #stackposition INT=2,
#sql NVARCHAR(max),
#cnt INT=1
SET #sql =' SELECT pkTestInstanceID,
[percent],
[count]
FROM #piv AS p
CROSS APPLY ( VALUES '
WHILE #cnt <= #stackposition
BEGIN
SET #sql+='([Percent' + CONVERT(VARCHAR(10), #cnt)+ '],[Count' + CONVERT(VARCHAR(10), #cnt) + ']),'
SET #cnt+=1
END
SET #sql= LEFT(#sql, Len(#sql) - 1)
SET #sql+=') AS x([percent], [count])'
EXEC Sp_executesql
#sql
OUTPUT
pkTestInstanceID percent count
---------------- ------- -----
1 25 1
1 75 3
2 50 2
2 50 2
You don't really need to pivot here. You can do a UNION on the resultset as suggested by #bksi like below
select pkTestInstanceID, percent1 as [percent], count1 as count
from (
inner result set
) tab
UNION
select pkTestInstanceID, percent2, count2
from (
inner result set
) tab1

Querying a junction/link/bridge table, column data as header

I have a list of specialties (upwards of 20)
SpecialtyID Description
------------------------
1 Specialty1
2 Specialty2
3 Specialty3
I have a list of providers (upwards of 50)
ProviderID Name
------------------------
1 Tom
2 Maria
3 Pat
Each provider can have multiple specialties, each specialty can have multiple providers - so a many to many relationship.
I have a junction/link/bridge table called SpecialtyProvider and if I simply query the link table with the following query, I get the table below.
SELECT SpecialtyID, ProviderID FROM SpecialtyProvider
SpecialtyID ProviderID
------------------------
1 1
2 1
3 1
1 2
2 2
3 3
What I would like to do, is pull out the data formatted like so:
SpecialtyID ProviderID=1 ProviderID=2 ProviderID=3 ProviderID=x
-----------------------------------------------------------
1 true true NULL
2 true true NULL
3 true NULL true
Once I can format the data correctly, I'll be dumping this into an ASP ListView.
I am not quite sure how to proceed. I have read 100 posts about different variations of the PIVOT command, but where I don't have an aggregate function, I haven't been able to make any of the other examples/solutions/groupings make sense.
If you need to pivot without using an aggregate, you can usually just use MAX (you're essentially taking the MAX of a single value, which is just that same value).
select SpecialtyID, case when [1] is not null then 'true' end 'ProviderID=1',
case when [2] is not null then 'true' end 'ProviderID=2',
case when [3] is not null then 'true' end 'ProviderID=3'
from (
select s.SpecialtyID, s.Description, sp.ProviderID
from Specialty s
join SpecialtyProvider sp on sp.SpecialtyID = s.SpecialtyID
) x
pivot(
MAX(Description)
for ProviderID in ([1],[2],[3])
) pvt
SQL Fiddle
However, it's also possible to get the same results without using PIVOT at all:
select s.SpecialtyID,
Max(case when sp.ProviderID = 1 then 'true' end) 'ProviderID=1',
Max(case when sp.ProviderID = 2 then 'true' end) 'ProviderID=2',
Max(case when sp.ProviderID = 3 then 'true' end) 'ProviderID=3'
from Specialty s
join SpecialtyProvider sp on sp.SpecialtyID = s.SpecialtyID
group by s.SpecialtyID
I find this easier to read, and it will probably be faster as well.
SQL Fiddle
With all that said, you may want to reconsider your UI. Having a table 50 columns wide will be difficult for a user to process. It might make sense to filter the data so the user can only view specific portions of it. Also, if you're dealing with a variable number of providers, it may make sense to pull all the data up to the web server and process it in your ASP codebehind.
The following blog post introduces the concept of a dynamic pivot where you do not have to specify you columns so as to address the X factor for Providers. http://beyondrelational.com/modules/2/blogs/70/posts/10840/dynamic-pivot-in-sql-server-2005.aspx
I took it a bit further and also print out the generated SQL. Here is what I came up for to address your example above.
IF (OBJECT_ID(N'dynamic_pivot', N'P') IS NOT NULL)
DROP PROCEDURE dynamic_pivot
GO
CREATE PROCEDURE dynamic_pivot
(
#select VARCHAR(2000)
, #PivotCol VARCHAR(100)
, #Summaries VARCHAR(100)
, #GenerateScript BIT = 1
)
AS
BEGIN
SET NOCOUNT ON ;
DECLARE #pivot VARCHAR(MAX)
, #sql VARCHAR(MAX)
SELECT #select = REPLACE(#select, 'SELECT ',
'SELECT ' + #PivotCol + ' AS pivot_col, ')
CREATE TABLE #pivot_columns
(
pivot_column VARCHAR(100)
)
SELECT #sql = 'SELECT DISTINCT pivot_col FROM (' + #select + ') AS t'
INSERT INTO #pivot_columns
EXEC ( #sql
)
SELECT #pivot = COALESCE(#pivot + ',', '') + '[' + pivot_column + ']'
FROM #pivot_columns
SELECT #sql = '
SELECT *
FROM
(
' + #select + '
) AS t
PIVOT
(
' + #Summaries + ' for pivot_col in (' + #pivot + ')
) AS p'
PRINT #sql
EXEC(#sql)
END
GO
EXEC [dbo].[dynamic_pivot] #select = 'SELECT SpecialtyID, 1 AS hasSpecialty FROM SpecialtyProvider', -- varchar(2000)
#PivotCol = 'ProviderID', -- varchar(100)
#Summaries = 'COUNT(hasSpecialty)' -- varchar(100)
The resulting query that is displayed in your message window in SSMS is the following:
SELECT *
FROM
(
SELECT ProviderID AS pivot_col, SpecialtyID, 1 AS hasSpecialty FROM SpecialtyProvider
) AS t
PIVOT
(
COUNT(hasSpecialty) for pivot_col in ([1],[2],[3])
) AS p
You can modify this to give you the column names and values that are required.

Stored procedure that returns a table from 2 combined

I am trying to write a stored procedure which returns a result combining 2 table variables which looks something like this.
Name | LastName | course | course | course | course <- Columns
Name | LastName | DVA123 | DVA222 | nothing | nothing <- Row1
Pete Steven 200 <- Row2
Steve Lastname 50 <- Row3
From these 3 tables
Table Staff:
Name | LastName | SSN |
Steve Lastname 234
Pete Steven 132
Table Course Instance:
Course | Year | Period |
DVA123 2013 1
DVA222 2014 2
Table Attended by:
Course | SSN | Year | Period | Hours |
DVA123 234 2013 1 200
DVA222 132 2014 2 50
I am taking #year as a parameter that will decide what year in the course will be displayed in the result.
ALTER proc [dbo].[test4]
#year int
as
begin
-- I then declare the 2 tables which I will then store the values from the tables
DECLARE #Table1 TABLE(
Firstname varchar(30) NOT NULL,
Lastname varchar(30) NOT NULL
);
DECLARE #Table2 TABLE(
Course varchar(30) NULL
);
Declare #variable varchar(max) -- variable for saving the cursor value and then set the course1 to 4
I want at highest 4 results/course instances which I later order by the period of the year
declare myCursor1 CURSOR
for SELECT top 4 period from Course instance
where year = #year
open myCursor1
fetch next from myCursor1 into #variable
--print #variable
while ##fetch_status = 0
Begin
UPDATE #Table2
SET InstanceCourse1 = #variable
where current of myCursor1
fetch next from myCursor1 into #variable
print #variable
End
Close myCursor1
deallocate myCursor1
insert into #table1
select 'Firstname', 'Lastname'
insert into #table1
select Firstname, Lastname from staff order by Lastname
END
select * from #Table1 -- for testing purposes
select * from #Table2 -- for testing purposes
--Then i want to combine these tables into the output at the top
This is how far I've gotten, I don't know how to get the courses into the columns and then get the amount of hours for each staff member.
If anyone can help guide me in the right direction I would be very grateful. My idea about the cursor was to get the top (0-4) values from the top4 course periods during that year and then add them to the #table2.
Ok. This is not pretty. It is a really ugly dynamic sql, but in my testing it seems to be working. I have created an extra subquery to get the courses values as the first row and then Union with the rest of the result. The top four courses are gathered by using ROW_Number() and order by Year and period. I had to make different versions of the courses string I am creating in order to use them for both column names, and in my pivot. Give it a try. Hopefully it will work on your data as well.
DECLARE #Year INT
SET #Year = 2014
DECLARE #Query NVARCHAR(2000)
DECLARE #CoursesColumns NVARCHAR(2000)
SET #CoursesColumns = (SELECT '''' + Course + ''' as c' + CAST(ROW_NUMBER() OVER(ORDER BY Year, Period) AS nvarchar(50)) + ',' AS 'data()'
FROM AttendedBy where [Year] = #Year
for xml path(''))
SET #CoursesColumns = LEFT(#CoursesColumns, LEN(#CoursesColumns) -1)
SET #CoursesColumns =
CASE
WHEN CHARINDEX('c1', #CoursesColumns) = 0 THEN #CoursesColumns + 'NULL as c1, NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c2', #CoursesColumns) = 0 THEN #CoursesColumns + ',NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c3', #CoursesColumns) = 0 THEN #CoursesColumns + ', NULL as c3, NULL as c4'
WHEN CHARINDEX('c4', #CoursesColumns) = 0 THEN #CoursesColumns + ', NULL as c4'
ELSE #CoursesColumns
END
DECLARE #Courses NVARCHAR(2000)
SET #Courses = (SELECT Course + ' as c' + CAST(ROW_NUMBER() OVER(ORDER BY Year, Period) AS nvarchar(50)) + ',' AS 'data()'
FROM AttendedBy where [Year] = #Year
for xml path(''))
SET #Courses = LEFT(#Courses, LEN(#Courses) -1)
SET #Courses =
CASE
WHEN CHARINDEX('c1', #Courses) = 0 THEN #Courses + 'NULL as c1, NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c2', #Courses) = 0 THEN #Courses + ',NULL as c2, NULL as c3, NULL as c4'
WHEN CHARINDEX('c3', #Courses) = 0 THEN #Courses + ', NULL as c3, NULL as c4'
WHEN CHARINDEX('c4', #Courses) = 0 THEN #Courses + ', NULL as c4'
ELSE #Courses
END
DECLARE #CoursePivot NVARCHAR(2000)
SET #CoursePivot = (SELECT Course + ',' AS 'data()'
FROM AttendedBy where [Year] = #Year
for xml path(''))
SET #CoursePivot = LEFT(#CoursePivot, LEN(#CoursePivot) -1)
SET #Query = 'SELECT Name, LastName, c1, c2, c3, c4
FROM (
SELECT ''Name'' as name, ''LastName'' as lastname, ' + #CoursesColumns +
' UNION
SELECT Name, LastName,' + #Courses +
' FROM(
SELECT
s.Name
,s.LastName
,ci.Course
,ci.Year
,ci.Period
,CAST(ab.Hours AS NVARCHAR(100)) AS Hours
FROM Staff s
LEFT JOIN AttendedBy ab
ON
s.SSN = ab.SSN
LEFT JOIN CourseInstance ci
ON
ab.Course = ci.Course
WHERE ci.Year=' + CAST(#Year AS nvarchar(4)) +
' ) q
PIVOT(
MAX(Hours)
FOR
Course
IN (' + #CoursePivot + ')
)q2
)q3'
SELECT #Query
execute(#Query)
Edit: Added some where clauses so only courses from given year is shown. Added Screenshot of my results.
try this
DECLARE #CourseNameString varchar(max),
#query AS NVARCHAR(MAX);
SET #CourseNameString=''
select #CourseNameString = STUFF((SELECT distinct ',' + QUOTENAME(Course)
FROM Attended where [Year]= 2013
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = '
select Name,LastName,'+#CourseNameString+' from Staff as e inner join (
SELECT * FROM
(SELECT [Hours],a.SSN,a.Course as c FROM Attended as a inner JOIN Staff as s
ON s.SSN = s.SSN) p
PIVOT(max([Hours])FOR c IN ('+#CourseNameString+')) pvt)p
ON e.SSN = p.SSN'
execute(#query)
Use subquery like this one :
SELECT Firstname, Lastname, (select instanceCourse1 from table2) as InstanceCourse1 from Table1