How to pivot multiple columns without aggregation - sql

I use SqlServer and i have to admit that i'm not realy good with it ...
This might be and easy question for the advanced users (I hope)
I have two tables which look like this
First table (ID isn't the primary key)
ID IdCust Ref
1 300 123
1 300 124
2 302 345
And the second (ID isn't the primary key)
ID Ref Code Price
1 123 A 10
1 123 Y 15
2 124 A 14
3 345 C 18
In the second table, the column "Ref" is the foreign key of "Ref" in the first table
I'm trying to produce the following output:
[EDIT]
The column "Stock", "Code" and "Price" can have x values, so I don't know it, in advance...
I tried so many things like "PIVOT" but it didn't give me the right result, so i hope someone can solve my problem ...

Use row_number() function and do the conditional aggregation :
select id, IdCust, Ref,
max(case when Seq = 1 then stock end) as [Stock A], -- second table *id*
max(case when Seq = 1 then code end) as [Code 1],
max(case when Seq = 1 then price end) as [Price1],
max(case when Seq = 2 then stock end) as [Stock B], -- second table *id*
max(case when Seq = 2 then code end) as [Code 2],
max(case when Seq = 2 then price end) as [Price2]
from (select f.*, s.Id Stock, s.Code, s.Price,
row_number() over (partition by f.Ref order by s.id) as Seq
from first f
inner join second s on s.Ref = f.Ref
) t
group by id, IdCust, Ref;
However, this would go with known values else you would need go with dynamic solution for that.

#YogeshSharma's provided an excellent answer.
Here's the same done using Pivot; SQL Fiddle Demo.
Functionally there's no difference between the two answers. However, Yogesh's solution's simpler to understand, and performs better; so personally I'd opt for that... I included this answer only because you mention PIVOT in the question:
select ft.Id
, ft.IdCust
, ft.Ref
, x.Stock1
, x.Code1
, x.Price1
, x.Stock2
, x.Code2
, x.Price2
from FirstTable ft
left outer join (
select Ref
, max([Stock1]) Stock1
, max([Stock2]) Stock2
, max([Code1]) Code1
, max([Code2]) Code2
, max([Price1]) Price1
, max([Price2]) Price2
from
(
select Ref
, Id Stock
, Code
, Price
, ('Stock' + cast(Row_Number() over (partition by Ref order by Id, Code) as nvarchar)) StockLineNo
, ('Code' + cast(Row_Number() over (partition by Ref order by Id, Code) as nvarchar)) CodeLineNo
, ('Price' + cast(Row_Number() over (partition by Ref order by Id, Code) as nvarchar)) PriceLineNo
from SecondTable
) st
pivot (max(Stock) for StockLineNo in ([Stock1],[Stock2])) pvtStock
pivot (max(Code) for CodeLineNo in ([Code1],[Code2])) pvtCode
pivot (max(Price) for PriceLineNo in ([Price1],[Price2])) pvtPrice
Group by Ref
) x
on x.Ref = ft.Ref
order by ft.Ref
Like Yogesh's solution, this will only handle as many columns as you specify; it won't dynamically alter the number of columns to match the data. For that you'd need to do dynamic SQL. However; if you need to do that, it's more likely you're attempting to solve the problem in the wrong way... so consider your design / determine if you really need additional columns per result rather than additional rows / some alternate approach...
Here's a Dynamic SQL implementation based on #YogeshSharma's answer: DBFiddle
declare #sql nvarchar(max) = 'select id, IdCust, Ref'
select #sql = #sql + '
,max(case when Seq = 1 then stock end) as [Stock' + rowNumVarchar + ']
,max(case when Seq = 1 then code end) as [Code' + rowNumVarchar + ']
,max(case when Seq = 1 then price end) as [Price' + rowNumVarchar + ']
'
from
(
select distinct cast(row_number() over (partition by ref order by ref) as nvarchar) rowNumVarchar
from second s
) z
set #sql = #sql + '
from (select f.*, s.Id Stock, s.Code, s.Price,
row_number() over (partition by f.Ref order by s.id) as Seq
from first f
inner join second s on s.Ref = f.Ref
) t
group by id, IdCust, Ref;
'
print #sql --see what the SQL produced is
exec (#sql)
(Here's a SQL Fiddle link for this one; but it's not working despite the SQL being valid

Related

How to get data from 2 rows which has same data in all columns except one in MSSQL

As in my title I want to take data from 2 rows but In my case each 2nd row has one different value compare to the first row.
I want to take all the common data along with the different data as a single row .
Here you can see each row has same values in another row except the 2nd rows last column.
Thanks.
Edits Result :
I suspect you have a some kind of ordering columns that could specify your actual data ordering if so, then you can use row_number() function
select * from (
select *,
row_number() over (partition by <common data cols> order by ? desc) Seq
from table t
) t
where seq = 1;
EDIT : I don't believe your inventort_item_id columns but yes you could use creation_date for ordering purpose
SELECT
EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE,
BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION AS POPULAR_PRODUCTS_IMAGE_PATHS
FROM (SELECT *,
ROW_NUMBER() OVER (PARTITION BY ITEM_CODE ORDER BY creation_date DESC) as Seq
FROM ECOM_PRODUCT_IMAGES EPI
) EPI
INNER JOIN ECOM_POPULAR_PRODUCTS_MAPPING EPPIM ON EPPIM.ITEM_CODE = EPI.ITEM_CODE
INNER JOIN LOM_MST_PRODUCT LMP ON LMP.PROD_CODE = EPI.ITEM_CODE
INNER JOIN LOM_LNK_PROD_COMP LLPC ON LLPC.COLOC_PROD_CODE = LMP.PROD_CODE
WHERE EPI.Seq = 1 AND
EPPIM.ITEM_STATUS = 'ACTIVE';
EDIT 2: In that case you need to use GROUP BY clause with conditional aggregation
SELECT
EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE,
MAX(CASE WHEN EPI.Seq = 2
THEN (BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION)
END) AS POPULAR_PRODUCTS_IMAGE_PATHS,
MAX(CASE WHEN EPI.Seq = 1
THEN (BASE_PATH + '' + EPI.IMAGE_FOLDER_NAME + '/' + EPI.IMAGE_DESCRIPTION)
END) AS PATH_NEW
FROM (SELECT *,
ROW_NUMBER() OVER (PARTITION BY ITEM_CODE ORDER BY creation_date DESC) as Seq
FROM ECOM_PRODUCT_IMAGES EPI
) EPI
INNER JOIN ECOM_POPULAR_PRODUCTS_MAPPING EPPIM ON EPPIM.ITEM_CODE = EPI.ITEM_CODE
INNER JOIN LOM_MST_PRODUCT LMP ON LMP.PROD_CODE = EPI.ITEM_CODE
INNER JOIN LOM_LNK_PROD_COMP LLPC ON LLPC.COLOC_PROD_CODE = LMP.PROD_CODE
WHERE EPPIM.ITEM_STATUS = 'ACTIVE'
GROUP BY EPI.ITEM_CODE, LMP.PROD_DESC, LLPC.COLOC_PROD_PRICE;
here is my approach, also using a window function.
sample data
if object_id('tempdb..#x') is not null drop table #x
CREATE TABLE #x (ITEM_CODE VARCHAR(10), PROD_DESC VARCHAR(20),
COLOR_PROD_PRICE DECIMAL, POPULAR_PRODUCTS_IMAGE_PATHS VARCHAR(200))
INSERT INTO #X(ITEM_CODE,PROD_DESC,COLOR_PROD_PRICE,POPULAR_PRODUCTS_IMAGE_PATHS) VALUES
('P0001', 'Axe Brand', 88.000, 'some_path_to_img1.jpg'),
('P0001', 'Axe Brand', 88.000, 'some_path_to_img2.jpg'),
('P0002', 'Almond Nuts', 499.000, 'some_path_to_img1.jpg'),
('P0002', 'Almond Nuts', 499.000, 'some_path_to_img2.jpg')
query - just change #x to your table and it should work
;WITH my_cte as
(
SELECT *,
ROW_NUMBER() OVER(PARTITION BY ITEM_CODE ORDER BY POPULAR_PRODUCTS_IMAGE_PATHS) AS 'track_row'
FROM #x
)
SELECT a.ITEM_CODE, a.PROD_DESC, a.COLOR_PROD_PRICE,
a.POPULAR_PRODUCTS_IMAGE_PATHS + ' ' + b.POPULAR_PRODUCTS_IMAGE_PATHS AS 'POPULAR_PRODUCTS_IMAGE_PATHS'
FROM my_cte AS a
INNER JOIN
my_cte AS b ON a.ITEM_CODE=b.ITEM_CODE
WHERE a.track_row=1 AND b.track_row=2
output
ITEM_CODE PROD_DESC COLOR_PROD_PRICE POPULAR_PRODUCTS_IMAGE_PATHS
P0001 Axe Brand 88 some_path_to_img1.jpg some_path_to_img2.jpg
P0002 Almond Nuts 499 some_path_to_img1.jpg some_path_to_img2.jpg

How to add a count/sum and group by in a CTE

Just a question on displaying a row on flight level and displaying a count on how many crew members on that flight.
I want to change the output so it will only display a single record at flight level and it will display two additional columns. One column (cabincrew) is the count of crew members that have the 'CREWTYPE' = 'F' and the other column (cockpitcrew) is the count of crew members that have the `'CREWTYPE' = 'C'.
So the query result should look like:
Flight DepartureDate DepartureAirport CREWBASE CockpitCrew CabinCrew
LS361 2016-05-19 BFS BFS 0 3
Can I have a little help tweaking the below query please:
WITH CTE AS (
SELECT cd.*, c.*, l.Carrier, l.FlightNumber, l.Suffix, l.ScheduledDepartureDate, l.ScheduledDepartureAirport
FROM
(SELECT *, ROW_NUMBER() OVER(PARTITION BY LegKey ORDER BY UpdateID DESC) AS RowNumber FROM Data.Crew) c
INNER JOIN
Data.CrewDetail cd
ON c.UpdateID = cd.CrewUpdateID
AND cd.IsPassive = 0
AND RowNumber = 1
INNER JOIN
Data.Leg l
ON c.LegKey = l.LegKey
)
SELECT
sac.Airline + CAST(sac.FlightNumber AS VARCHAR) + sac.Suffix AS Flight
, sac.DepartureDate
, sac.DepartureAirport
, sac.CREWBASE
, sac.CREWTYPE
, sac.EMPNO
, sac.FIRSTNAME
, sac.LASTNAME
, sac.SEX
FROM
Staging.SabreAssignedCrew sac
LEFT JOIN CTE cte
ON sac.Airline + CAST(sac.FlightNumber AS VARCHAR) + sac.Suffix = cte.Carrier + CAST(cte.FlightNumber AS VARCHAR) + cte.Suffix
AND sac.DepartureDate = cte.ScheduledDepartureDate
PLEASE TRY THIS.
SELECT Flight,
DepartureDate,
DepartureAirport,
CREWBASE,
SUM(CASE WHEN CREWTYPE = 'F' THEN 1 ELSE 0 END) AS CabinCrew ,
SUM(CASE WHEN CREWTYPE = 'C' THEN 1 ELSE 0 END) AS CockpitCrew
FROM #Table
GROUP BY Flight, DepartureDate, DepartureAirport, CREWBASE
Please Try This:
select Flight, DepartureDate, DepartureAirport,CREWBASE,
count(case when CREWTYPE='F' then 1 end ) as CabinCrew,count(case when CREWTYPE='C' then 1 end ) as CockpitCrew
from Staging.SabreAssignedCrew
group by Flight, DepartureDate, DepartureAirport,CREWBASE

How to convert rows into column in sql

I have a table,
and need to convert it as
I have tried pivot but can't figure out please help me out .
Pivot does not work with more than one column out-of-the-box There are several approaches to solve this:
Use this table variable for all tests and please state your sample data always copy'n'pasteable. Best was a MCVE (Minimal Complete Verifyable Example) where you set up some code like mine here.
DECLARE #tbl TABLE(ID INT, Code INT,EmployeeName VARCHAR(100),ExamName VARCHAR(100),Board VARCHAR(100),Result VARCHAR(100));
INSERT INTO #tbl VALUES
(11537,12984,'TheName','SSC','b04','1st')
,(11537,12984,'TheName','HSC','b04','2nd')
,(11537,12984,'TheName','BA(H)','u33','2nd');
This is code to first concatenate your data to one single column. This allows PIVOT:
SELECT p.*
FROM
(
SELECT tbl.ID
,tbl.Code
,tbl.EmployeeName
,'Exam_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.ID ORDER BY tbl.Code) AS VARCHAR(100)) AS ColName
,ExamName + ' (' + Board + '): ' + Result AS Concatenated
FROM #tbl AS tbl
) AS t
PIVOT
(
MIN(Concatenated) FOR ColName IN(Exam_1,Exam_2,Exam_3 /*add as many as you need*/)
) AS p
The result:
11537 12984 TheName SSC (b04): 1st HSC (b04): 2nd BA(H) (u33): 2nd
The next code does quite the same, but creates XML instead of plain text, which allows to separate your data afterwards:
SELECT p.ID
,p.Code
,p.EmployeeName
,E1
,E1.value('(/exam/#ExamName)[1]','varchar(100)') AS ExamName1
,E1.value('(/exam/#Board)[1]','varchar(100)') AS Board1
,E1.value('(/exam/#Result)[1]','varchar(100)') AS Result1
,E2
,E2.value('(/exam/#ExamName)[1]','varchar(100)') AS ExamName2
,E2.value('(/exam/#Board)[1]','varchar(100)') AS Board2
,E2.value('(/exam/#Result)[1]','varchar(100)') AS Result2
,E3
,E3.value('(/exam/#ExamName)[1]','varchar(100)') AS ExamName3
,E3.value('(/exam/#Board)[1]','varchar(100)') AS Board3
,E3.value('(/exam/#Result)[1]','varchar(100)') AS Result3
FROM
(
SELECT tbl.ID
,tbl.Code
,tbl.EmployeeName
,'Exam_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.ID ORDER BY tbl.Code) AS VARCHAR(100)) AS ColName
,(SELECT ExamName AS [#ExamName],Board AS [#Board],Result AS [#Result] FOR XML PATH('exam')) AS AsXML
FROM #tbl AS tbl
) AS t
PIVOT
(
MIN(AsXML) FOR ColName IN(Exam_1,Exam_2,Exam_3 /*add as many as you need*/)
) AS p
OUTER APPLY
(
SELECT CAST(p.Exam_1 AS XML) AS E1
,CAST(p.Exam_2 AS XML) AS E2
,CAST(p.Exam_3 AS XML) AS E3
) AS CastedToXml
The result:
11537 12984 TheName <exam ExamName="SSC" Board="b04" Result="1st" /> SSC b04 1st <exam ExamName="HSC" Board="b04" Result="2nd" /> HSC b04 2nd <exam ExamName="BA(H)" Board="u33" Result="2nd" /> BA(H) u33 2nd
This is old-fashioned-pivot which is quite often better then normal pivot:
;WITH Numberd AS
(
SELECT *
,ROW_NUMBER() OVER(PARTITION BY tbl.ID ORDER BY tbl.Code) AS Number
FROM #tbl AS tbl
)
SELECT ID,Code,EmployeeName
,MAX(CASE WHEN Number=1 THEN ExamName END) AS ExamName1
,MAX(CASE WHEN Number=1 THEN Board END) AS Board1
,MAX(CASE WHEN Number=1 THEN Result END) AS Result1
,MAX(CASE WHEN Number=2 THEN ExamName END) AS ExamName2
,MAX(CASE WHEN Number=2 THEN Board END) AS Board2
,MAX(CASE WHEN Number=2 THEN Result END) AS Result2
,MAX(CASE WHEN Number=3 THEN ExamName END) AS ExamName3
,MAX(CASE WHEN Number=3 THEN Board END) AS Board3
,MAX(CASE WHEN Number=3 THEN Result END) AS Result3
FROM Numberd
GROUP BY ID,Code,EmployeeName
The last option was dynamic SQL...
Thnak you all , But My purpose is solved with this
SELECT
he.Id,he.Code,he.Name EmployeeName,en.Name [ExamName],bu.Name
[Board],[Result] = CASE WHEN
ac.GPA IS NULL THEN ac.Result ELSE CAST(ac.GPA AS VARCHAR) END,
ac.PassingYear
INTO #Temp
FROM H_Employee AS he
INNER JOIN
H_AcademicQualification AS ac ON ac.H_EmployeeId = he.Id
INNER JOIN
ExamName AS en ON en.Id = ac.ExamNameId
INNER JOIN
GroupSubject AS gs ON gs.Id = ac.GroupSubjectId
INNER JOIN
BoardUniversity AS bu ON bu.Id = ac.BoardUniversityId
Then
SELECT
a.id, a.Code, a.EmployeeName, a.ExamName, a.Board, a.Result, a.Passingyear,
b.ExamName, b.Board, b.Result, b.Passingyear,
c.ExamName, c.Board, c.Result, c.Passingyear,
d.ExamName, d.Board, d.Result, d.Passingyear
FROM
(SELECT
Id, Code, EmployeeName ,ExamName = CASE WHEN
ExamName LIKE 'S.S.%' THEN 'S.S.C' END,
Board=Board ,[Result]=CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'S.S.%') AS a
LEFT JOIN
(SELECT Id, Code, EmployeeName ,ExamName = CASE WHEN
ExamName LIKE 'H.S.%' THEN 'H.S.C' END,
Board=Board,[Result] = CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'H.S.%') AS b
ON a.Id=b.Id
LEFT JOIN
(SELECT Id, Code, EmployeeName ,ExamName = CASE WHEN
ExamName LIKE 'B.%' THEN 'Graduate' END,
Board=Board, [Result] = CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'B.%') AS c
ON a.Id=c.Id
LEFT JOIN
(SELECT Id, Code, EmployeeName, ExamName = CASE WHEN
ExamName LIKE 'M.%' THEN 'Post-Graduate' END,
Board=Board,[Result] = CASE WHEN
Result IS NULL THEN Result ELSE CAST(Result AS VARCHAR) END,
Passingyear
FROM #temp
WHERE ExamName LIKE 'M.%') AS d
ON a.Id=d.Id
Above query serve me purposes but will try #Shnugo Sample , Any way thank you all .

SQL: break column into multiple columns by cell value

I'm trying to build a module in VBA that will query 2 data sources and left join them on the common field of "Name". The problem is that the data are grained differently. The set I'm trying to change currently looks like this:
And I'm trying to make it look like this:
So that I can left join it with a query from my second dataset, which is grained by "name" rather than "item value".
FWIW, here's what the query I'm currently trying to run looks like. I'm using an implicit join to get "current value" and "past value" for each "name", but none of this refers to dataset 2:
with set1 as (SELECT NAME, ITEM_CODE, ITEM_VALUE_NUMBER as CURRENT_VALUE FROM [...] WHERE [...]),
with set2 as (SELECT NAME, ITEM_CODE, ITEM_VALUE_NUMBER as PAST_VALUE FROM [...] WHERE [...]),
SELECT set1.NAME [ITEM_1], [ITEM_2], [ITEM_3] from
(SELECT set1.NAME, set1.CURRENT_VALUE, set2.PAST_VALUE FROM set1, set2 WHERE set1.NAME=set2.NAME and set1.ITEM_CODE=set2.ITEM_CODE) AS SourceTable
PIVOT (max(CURRENT_VALUE) for ITEM_CODE in [ITEM_1], [ITEM_2], [ITEM_3]) AS PivotTable;
Thanks in advance for any guidance you can offer!
So, you have a couple options. First is trying to reword the pivot to get the results you want, which makes for a more complicated query than required. You can do this in the following way if you wish:
SELECT Name
, MAX(C1) Item1CurrentValue
, MAX(P1) Item1PastValue
, MAX(C2) Item2CurrentValue
, MAX(P2) Item2PastValue
, MAX(C3) Item3CurrentValue
, MAX(P3) Item3PastValue
FROM (
SELECT set1.Name
, 'C' + CAST(set1.ItemCode AS VARCHAR(255)) ItemCode1
, CurVal
, 'P' + CAST(set2.ItemCode AS VARCHAR(255)) ItemCode2
, PastVal
FROM (SELECT Name, ItemCode, ITEM_VALUE_NUMBER CurVal FROM myFirstQuery) set1
JOIN (SELECT Name, ItemCode, ITEM_VALUE_NUMBER PastVal FROM mySecondQuery) set2 ON set1.Name = set2.Name AND set1.ItemCode = set2.ItemCode) T
PIVOT (MAX(CurVal) FOR ItemCode1 IN (C1, C2, C3)) P1
PIVOT (MAX(PastVal) FOR ItemCode2 IN (P1, P2, P3)) P2
GROUP BY Name;
I don't really think CTEs make the query more readable so I just removed them, but you could use the CTEs in a similar fashion if you wish.
The better (and easier to understand, in my opinion) way is to just use conditional aggregation, like such:
SELECT Name
, MAX(CASE WHEN ItemCode = 1 THEN CurVal END) Item1CurrentValue
, MAX(CASE WHEN ItemCode = 1 THEN PastVal END) Item1PastValue
, MAX(CASE WHEN ItemCode = 2 THEN CurVal END) Item2CurrentValue
, MAX(CASE WHEN ItemCode = 2 THEN PastVal END) Item2PastValue
, MAX(CASE WHEN ItemCode = 3 THEN CurVal END) Item3CurrentValue
, MAX(CASE WHEN ItemCode = 3 THEN PastVal END) Item3PastValue
FROM (
SELECT set1.Name
, set1.ItemCode
, CurVal
, PastVal
FROM (SELECT Name, ItemCode, ITEM_VALUE_NUMBER CurVal FROM myFirstQuery) set1
JOIN (SELECT Name, ItemCode, ITEM_VALUE_NUMBER PastVal FROM mySecondQuery) set2 ON set1.Name = set2.Name AND set1.ItemCode = set2.ItemCode) T
GROUP BY Name;

Dynamic SubSelects in SQL Select Statement

I am querying a table for some basic information, file number, case type, status, etc. In addition I need a column for every single one of 138 case status types that will display the date the case had that status. Here is a sample:
SELECT FileNum,
CaseType,
CurrentCaseStatus,
(SELECT TOP 1 EventDt FROM caseStatusHistory WHERE CaseID = c.caseID AND CaseStatus = 'CS001' ORDER BY EventDt DESC) AS [Charge - Phone],
(SELECT TOP 1 EventDt FROM caseStatusHistory WHERE CaseID = c.caseID AND CaseStatus = 'CS002' ORDER BY EventDt DESC) AS [Charge - Written],
-- 136 more just like the live above
FROM Case c
I can query another table for all the case status types:
SELECT Code, Description
FROM caseStatus
WHERE Code BETWEEN 'CS001' AND 'CS138'
ORDER BY Code
How can I dynamically create each of those columns instead of having to manually write 138 select statements?
That's going to be terribly slow -- 138 correlated subqueries. I think you can achieve the same result with an OUTER JOIN and a GROUP BY with MAX and CASE:
Select c.filenum,
c.casetype,
c.currentcasestatus,
max(case when csh.CaseStatus = 'CS001' then EventDt end) as [Charge - Phone],
max(case when csh.CaseStatus = 'CS002' then EventDt end) as [Charge - Written]
from case c
left join casestatushistory csh on c.caseid = csh.caseid
group by c.filenum,
c.casetype,
c.currentcasestatus
BTW, I would suggest just writing the statement out -- it won't take that long and it will out perform a dynamic sql approach. I'm not completely sure how you'd get your column names with dynamic sql either unless Phone and Written are in another column.
Try using a PIVOT. The SQL below should work -
--Select the pivot data into a temp table
SELECT c.caseID,
c.FileNum,
c.CaseType,
c.CurrentCaseStatus,
csh.EventDt,
cs.Description
INTO #StatusDates
FROM [Case] c
LEFT JOIN caseStatusHistory csh
ON csh.caseID = c.caseID
LEFT JOIN caseStatus cs
ON cs.Code = csh.CaseStatus
--From the pivot data, get the list of field names (assumes description field is the source for the field name)
DECLARE #statusDescriptions VARCHAR(MAX)
SET #statusDescriptions = ''
SELECT #statusDescriptions = COALESCE(#statusDescriptions+'[','') + Description
FROM (
SELECT DISTINCT Description
FROM #StatusDates
WHERE Description IS NOT NULL
) x
SET #statusDescriptions = REPLACE(#statusDescriptions, '[', '],[') + ']'
SET #statusDescriptions = SUBSTRING(#statusDescriptions, 3, LEN(#statusDescriptions))
--Create a SQL statement to pivot the data into the fields.
DECLARE #sql VARCHAR(MAX)
SET #SQL = '
SELECT *
FROM #StatusDates
PIVOT(MIN(EventDt)
FOR Description IN (' + #statusDescriptions + '))
AS PVTTable '
PRINT #sql
EXEC(#sql)
DROP TABLE #StatusDates