SQL: Display the table and its job by yes and no - sql

This is my table:
User Table
Id | Username |
---------------
1 | jdoe |
Job Table
Id | Job |
----------------
1 | Waiter |
2 | Office |
3 | Freelance |
User Job Table
Id |UserId | JobId |
--------------------
1 | 1 | 2 |
2 | 1 | 3 |
How to select this table and display it to look like this below:
Id | Username | Waiter| Office | Freelance|
-------------------------------------------
1 | jdoe | No | Yes | Yes |

This is a pretty standard pivot query question, with an additional slight twist. In case a given user does not have a certain type of job assigned, you want to display 'No'. One way to do this is to make use of COALESCE and replace NULL job aggregates.
SELECT u.Id,
u.Username,
COALESCE(MAX(CASE WHEN j.Job = 'Waiter' THEN 'Yes' END), 'No') AS Waiter,
COALESCE(MAX(CASE WHEN j.Job = 'Office' THEN 'Yes' END), 'No') AS Office,
COALESCE(MAX(CASE WHEN j.Job = 'Freelance' THEN 'Yes' END), 'No') AS Freelance
FROM User u
LEFT JOIN User_Job uj
ON u.Id = uj.UserId
LEFT JOIN Job j
ON uj.JobId = j.Id
GROUP BY u.Id,
u.Username

Try this..
WITH cte AS
(
SELECT u.username,job,CASE WHEN uj.jobid IS NULL THEN 'No' ELSE 'yes' END AS jobid
FROM USER u INNER JOIN UserJob uj on u.id = uj.Userid
RIGHT JOIN Job j on j.id = uj.jobid
)
SELECT username,ISNULL(waiter,'no') waiter,
ISNULL(Office,'no') Office,
ISNULL(Freelance,'no') Freelance
FROM cte
PIVOT
(
MAX(jobid) FOR job IN (Waiter, Office,Freelance)
) piv
WHERE username IS NOT NULL

DECLARE #cols AS NVARCHAR(MAX),#Listcols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + 'Isnull('+QUOTENAME(t.Job) +',''No'') as ' + t.Job
from Job t
order by Job desc
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #Listcols = STUFF((SELECT ',' + QUOTENAME(t.Job)
from Job t
order by Job desc
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT Id, Username,' + #cols + N' from
(
select D1.Id, D1.Username,
COALESCE(CASE WHEN isnull(D2.UserId,0) > 0 THEN ''Yes''
Else ''No''
End, ''No'') as UserId,
D3.Job
from [User] D1
Inner Join User_Job D2
On D1.Id = D2.UserId
Inner Join Job D3
On D2.JobId = D3.Id
) x
pivot
(
max(UserId)
for Job in (' + #Listcols + N')
) p '
exec sp_executesql #query;

If the job items are come from a result.
CREATE TABLE #T1(id INT ,Username VARCHAR(100))
INSERT INTO #T1 SELECT 1,'jdoe'
CREATE TABLE #T2(id INT ,Job VARCHAR(100))
INSERT INTO #T2 VALUES(1,'Waiter'),(2,'Office'),(3,'Freelance')
CREATE TABLE #T3(id INT ,UserId INT ,JobId INT )
INSERT INTO #T3 VALUES(1,1,2),(2,1,3)
DECLARE #col NVARCHAR(max),#sql NVARCHAR(max)
SELECT #col=ISNULL(#col+',[','[')+Job+']' FROM #t2
PRINT #col
SET #sql='
SELECT * FROM (
SELECT uj.Job,uj.Username,CASE WHEN t3.UserId IS NULL THEN ''No'' ELSE ''Yes'' END AS f FROM (
SELECT t2.id AS JobId, t2.Job,t1.id AS UserId, t1.Username
FROM #T1 AS t1,#t2 AS t2
) uj LEFT JOIN #T3 AS t3 ON t3.JobId = uj.JobId AND t3.UserId = uj.UserId
) AS t PIVOT(MAX(f) FOR job IN ('+#col+')) p'
EXEC(#sql)

Related

Dynamic Cols Pivot Rows but only some columns, not all

I'm making a dynamic pivot table with a similar structure in the example below.
Query to list each child record in columns of a parent
EXCEPT, all the examples I seem to find, when building the list of dynamics columns for the pivot, they all use "quotename" to get all columns in the table, while I only want a handful for my output.
select #colsPivot = STUFF((SELECT ','
+ quotename(c.name +'_'+ cast(t.rn as varchar(10)))
from
(
select cast(row_number() over(partition by m.MemberID order by g.guestid) as varchar(50)) rn
from member m
left join guest g
on m.guestid = g.guestid
) t
cross apply sys.columns as C
where C.object_id = object_id('guest')
group by c.name, t.rn
order by t.rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
Wondering if anyone can help with the syntax. In the above example, instead of getting First name and Last Name, hypothetically, I only want Last Name. How would that look?
I'm just looking at how to replace the quotename properly, I believe I have the rest running properly.
SAMPLE:
Member Table
MemberID | FName | LName
001 Frank Smith
002 Mary Jane
003 John Henry
Guest Table
GuestID | FName | LName | MemberId
101 Steve Smith | 001
102 Peter Smith | 001
103 Mike Jane | 002
OUTPUT:
MemberID | FName | LName| GuestID1 | LName1 |GuestID2 | LName2
001 Frank Smith 101 Smith 102 Smith
002 Mary Jane 103 Jane
003 John Henry
Any and all help is much appreciated!
Key point is that we need to use row_number window function to make a row number and then use condition aggregate function to make it.
SELECT MemberID,FName,LName,
MAX(CASE WHEN rn = 1 THEN GuestID END) GuestID1,
MAX(CASE WHEN rn = 1 THEN g_LName END) LName1,
MAX(CASE WHEN rn = 2 THEN GuestID END) GuestID2,
MAX(CASE WHEN rn = 2 THEN g_LName END) LName2
FROM (
SELECT m.MemberID,
m.FName,
m.LName,
GuestID,
g.LName g_LName,
ROW_NUMBER() OVER(PARTITION BY m.MemberID ORDER BY GuestID) rn
FROM Member m LEFT JOIN Guest g
ON m.MemberId = g.MemberId
) t1
GROUP BY MemberID,FName,LName
if there might be multiple LName (more than 2) and you want to use Dynamic pivot you can try the below code, but that might be a little complex.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((
SELECT distinct ', MAX(CASE WHEN rn = '+ CAST(t1.cnt AS VARCHAR(5)) + ' THEN GuestID END)' + ' as '''+CONCAT(name,t1.cnt)+''''
FROM (SELECT COUNT(*) cnt FROM Guest GROUP BY MemberId) t1
CROSS JOIN (SELECT 'GuestID' name UNION ALL SELECT 'LName') t2
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT MemberID,FName,LName, ' + #cols + '
FROM (
SELECT m.MemberID,
m.FName,
m.LName,
GuestID,
g.LName g_LName,
ROW_NUMBER() OVER(PARTITION BY m.MemberID ORDER BY GuestID) rn
FROM Member m LEFT JOIN Guest g
ON m.MemberId = g.MemberId
) t1
GROUP BY MemberID,FName,LName '
execute(#query)
sqlfiddle

Dynamic Pivot Sql Query display all from one table

TABLE-A:-
Custno
Name
Route
Phone
1
C1
1
12345
2
C2
1
23456
3
C3
2
34567
4
C4
1
45678
5
C5
1
56789
TABLE-B:-
ODate
Custno
Route
ProductId
qty
2021-04-22
1
1
1
100
2021-04-22
1
1
3
200
2021-04-22
2
1
1
120
Table-C
ProductId
BrandName
1
Brand-1
2
Brand-2
3
Brand-3
EXPECTED RESULT
Phone
CustNo
Name
Brand-1
Brand-2
Brand-3
12345
1
C1
100
200
23456
2
C2
120
45678
4
C4
56789
5
C5
What I tried Using Dynamic Pivot
DECLARE #query AS VARCHAR(MAX)
, #cols_ AS vARCHAR(MAX)
--Making the column list dynamically
select #cols_ = STUFF((SELECT ',' + QUOTENAME(brandname) from [Table-C] order by productid FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)') ,1,1,'')
print #cols_
--preparing PIVOT query dynamically.
SET #query = ' SELECT
pivoted.*
into #Temp_data
FROM
(
select a.phone,a.custno,a.[name],d.BrandName,c.qty from [Table-A] a inner join [Table-B] c on a.custno = c.custno inner join [Table-C] d on c.productid = d.Productid and a.Route='1' and c.odate='2021-04-22'
) AS [p]
PIVOT
(
MIN([P].[qty])
FOR [P].[BrandName] IN (' + #cols_ + ')
) AS pivoted
order by custno;
select *
from #Temp_data [B]
-- GROUP BY [B].[ODate]
drop table #Temp_data
';
EXEC (#query)
You can reconstruct the query
SELECT *
FROM
(
SELECT A.[Phone], A.[CustNo], A.[Name], C.[BrandName], B.[qty]
FROM [Table-A] AS A
LEFT JOIN [Table-B] AS B
ON A.[CustNo] = B.[CustNo]
AND B.[odate] = '2021-04-22'
LEFT JOIN [Table-C] AS C on C.productid = B.Productid
WHERE A.[Route] = 1
) t
PIVOT
(
MIN([qty]) FOR [BrandName] IN ([Brand-1],[Brand-2],[Brand-3])
) AS piv
which contains LEFT JOIN rather than INNER JOIN, and STRING_AGG() function in order to generate the pivoted columns dynamically as in the following code block
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
SET #cols = ( SELECT STRING_AGG(QUOTENAME([BrandName]),',')
FROM (SELECT DISTINCT [BrandName]
FROM [Table-C] ) C );
SET #query =
N'SELECT *
FROM
(
SELECT A.[Phone], A.[CustNo], A.[Name], C.[BrandName], B.[qty]
FROM [Table-A] AS A
LEFT JOIN [Table-B] AS B
ON A.[CustNo] = B.[CustNo]
AND B.[odate] = ''2021-04-22''
LEFT JOIN [Table-C] AS C on C.productid = B.Productid
WHERE A.[Route] = 1
) t
PIVOT
(
MIN([qty]) FOR [BrandName] IN (' + #cols + N')
) AS piv'
EXEC sp_executesql #query;
Demo

Getting multiple MAX values from one-to-many table

I have two tables and I would like to get MAX(date) from one-to-many table. If there is no value, it should be NULL. Only way I know how to do it by making sub queries but if there is ~20 different types then 20 sub queries does not sound efficient enough. Is there any better way to do it?
Table A:
UserId | Name
1 | John
2 | Jane
Table B:
UserId | Type | Date
1 | A | 2015-01-01
1 | A | 2015-12-31
1 | B | 2015-01-01
1 | B | 2015-12-31
2 | B | 2015-06-06
1 | C | 2015-01-01
2 | C | 2015-09-09
Result:
UserId | Type A date | Type B date | Type C date
1 | 2015-12-31 | 2015-12-31 | NULL
2 | NULL | 2015-06-06 | 2015-09-09
Current solution:
SELECT UserId,
(SELECT MAX(Date) FROM B WHERE Type = 'A' AND B.UserId= A.UserId),
(SELECT MAX(Date) FROM B WHERE Type = 'B' AND B.UserId= A.UserId),
(SELECT MAX(Date) FROM B WHERE Type = 'C' AND B.UserId= A.UserId
AND Date > (SELECT MAX(Date) FROM B WHERE Type = 'B' AND B.UserId = A.UserId))
FROM A
Thank you for all quick answers! They work perfectly. I modified my question little bit since I noticed that I need to add some conditions on some types. For example. Type C should be only presented if it's bigger than type B.
To get the expected result you don't even need to join, simply do a group by and use case expressions do to conditional aggregation:
select userid,
max(case when type = 'A' then date end) Adate,
max(case when type = 'B' then date end) Bdate
from tableB
group by userid
If you also want the username, you can join tableA with the above query:
select a.name, b.Adate, b.Bdate
from tableA a
join (select userid,
max(case when type = 'A' then date end) Adate,
max(case when type = 'B' then date end) Bdate
from tableB
group by userid) b
on a.userid = b.userid
However, if the number of types is unknown, I'd group by the column type too. I.e return types in different rows.
select a.name, b.type, b.date
from tableA a
left join (select userid, type, max(date) date,
from tableB
group by userid, type) b
on a.userid = b.userid
You can do a conditional aggregation instead of the subqueries in the SELECT:
SELECT
a.UserId,
MAX(CASE WHEN b.Type = 'A' THEN b.date END) AS ADate,
MAX(CASE WHEN b.Type = 'B' THEN b.date END) AS BDate
FROM TableA a
LEFT JOIN TableB b
ON b.UserId = a.UserId
GROUP BY a.UserId;
However, the above will only work if you know the values of Type. If you don't, then you need to do it using a dynamic query.
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
a.UserId' + CHAR(10) +
(SELECT DISTINCT
' , MAX(CASE WHEN b.Type = ''' + Type + ''' THEN b.Date END) AS ' + QUOTENAME(Type + 'Date') + CHAR(10)
FROM TableB
FOR XML PATH('')
) +
'FROM TableA a
LEFT JOIN TableB b
ON b.UserId = a.UserId
GROUP BY a.UserId;';
EXEC (#sql);
ONLINE DEMO
Reference: Cross Tabs and Pivots by Jeff Moden
Use Dynamic Pivot, no matter how many type you have, you dont need to change the query.
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME([TYPE])
FROM (SELECT DISTINCT [TYPE] as [TYPE] FROM [master].[dbo].[YourTable]) AS TypeTable
SET #DynamicPivotQuery =
'SELECT USERID,' + #ColumnName+'
FROM [master].[dbo].[YourTable]
PIVOT(MAX([Date])
FOR [TYPE] IN (' + #ColumnName+')) AS PVTTable'
EXEC sp_executesql #DynamicPivotQuery
Result is like below :
USERID A B
1 2015-12-31 2015-12-31
2 NULL 2015-06-06
Edit : For type C,there are some condition:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
DECLARE #ColumnNameForDisplay AS NVARCHAR(MAX)
DECLARE #otherCondition AS NVARCHAR(MAX)
SELECT #ColumnName = ISNULL(#ColumnName + ',','') + QUOTENAME([TYPE])
FROM (SELECT DISTINCT [TYPE] as [TYPE] FROM [master].[dbo].[YourTable]) AS TypeTable
SELECT #ColumnNameForDisplay = ISNULL(#ColumnNameForDisplay + ',','') + [TYPE2]
FROM (SELECT DISTINCT [TYPE]+' as [Type '+[TYPE]+' date]' as [TYPE2] FROM [master].[dbo].[YourTable] where type <> 'c') AS TypeTable
SELECT #otherCondition = ' ,Case when c <= b then null else c END as [Type C date] '
SET #DynamicPivotQuery = '
SELECT USERID,'+#ColumnNameForDisplay+#otherCondition+' from(
SELECT USERID,' + #ColumnName+'
FROM [master].[dbo].[YourTable]
PIVOT(MAX([Date])
FOR [TYPE] IN (' + #ColumnName+')) AS PVTTable) as t'
EXEC sp_executesql #DynamicPivotQuery
Result is like below :
USERID Type A date Type B date Type C date
1 2015-12-31 2015-12-31 NULL
2 NULL 2015-06-06 2015-09-09

Format Jagged data gained from dynamic pivot

I need to format and extract some data from a database. While I can extract the data successfully I am struggling with the jagged nature of it.
What I have is the following:
create table temp
(
QuestionID INT,
AnswerID INT,
AnswerValue NVARCHAR(50)
)
insert into temp values (1, 1, 'Ans C')
insert into temp values (1, 2, 'Ans B')
insert into temp values (1, 3, 'Ans A')
insert into temp values (2, 4, 'Ans D')
insert into temp values (2, 5, 'Ans E')
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.AnswerID)
FROM temp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT QuestionID, ' + #cols + ' from
(
select QuestionID
, AnswerValue
, AnswerID
from temp
) x
pivot
(
max(AnswerValue)
for AnswerID in (' + #cols + ')
) p '
execute(#query)
drop table temp
Executed this produces
+------------+-------+-------+-------+-------+-------+
| QuestionID | 1 | 2 | 3 | 4 | 5 |
+------------+-------+-------+-------+-------+-------+
| 1 | Ans C | Ans B | Ans A | NULL | NULL |
| 2 | NULL | NULL | NULL | Ans D | Ans E |
+------------+-------+-------+-------+-------+-------+
I just need to format it like this
+------------+-------+-------+-------+
| QuestionID | Q1 | Q2 | Q3 |
+------------+-------+-------+-------+
| 1 | Ans C | Ans B | Ans A |
| 2 | NULL | Ans D | Ans E |
+------------+-------+-------+-------+
Note due to restrictions this needs to be done in SQL rather than an advanced language such as c#.
A few things are wrong with the code. First, you are creating your column list using the AnswerID so the data is being split across multiple columns instead of the Answer for each question.
In order to fix this, you'll want to use a windowing function like row_number() to create a sequence for each question/answer combination.
When creating your dynamic columns change the code to be:
SET #cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10)))
FROM
(
SELECT rn = row_number() over(partition by QuestionID
order by AnswerID)
FROM temp
) c
group by rn
order by rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
This will use row_number() and will create the column names based on the QuestionID. Then you'll include the row_number() in your subquery making your code:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT ',' + QUOTENAME('Q'+cast(rn as varchar(10)))
FROM
(
SELECT rn = row_number() over(partition by QuestionID
order by AnswerID)
FROM temp
) c
group by rn
order by rn
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT QuestionID, ' + #cols + '
from
(
select QuestionID
, AnswerValue
, col = ''Q''+ cast(row_number() over(partition by QuestionID
order by AnswerID) as varchar(10))
from temp
) x
pivot
(
max(AnswerValue)
for col in (' + #cols + ')
) p '
exec sp_executesql #query;
See SQL Fiddle with Demo. This gives a result:
| QUESTIONID | Q1 | Q2 | Q3 |
|------------|-------|-------|--------|
| 1 | Ans C | Ans B | Ans A |
| 2 | Ans D | Ans E | (null) |
You can use this part of code:
SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers
in order to generate the column names required. The above gives you sth like:
cName
-----
A1
A2
A3
A1
A2
You can subsequently use the above in your dynamic pivot to obtain the desired result:
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(a.cName)
FROM (
SELECT 'A' + CAST(ROW_NUMBER() OVER(PARTITION BY QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers
) a
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT Question, ' + #cols + ' ' +
'FROM (
SELECT q.Question, a.Answer,
''A'' + CAST(ROW_NUMBER() OVER(PARTITION BY a.QuestionID ORDER BY Answer) AS VARCHAR(10)) AS cName
FROM tblAnswers AS a
INNER JOIN tblQuestions AS q ON a.QuestionID = q.QuestionID
) t
PIVOT
(
MAX(t.Answer)
FOR cName in (' + #cols + ')
) Pvt '
execute(#query)
Output from above looks like:
Question A1 A2 A3
-----------------------------------
Q1 Answer1 Answer2 Answer3
Q2 Answer4 Answer5 NULL
SQL Fiddle demo here

Pivot Table with many to many table

My SQL Fiddle is here: http://sqlfiddle.com/#!3/d5c60
CREATE TABLE customer
(
id int identity primary key,
name varchar(20),
);
CREATE TABLE warehouse
(
id int identity primary key,
name varchar(20),
);
CREATE TABLE customerwarehouse
(
id int identity primary key,
customerid int,
warehouseid int
);
INSERT INTO customer (name)
VALUES
('CustA'),
('CustB'),
('CustC');
INSERT INTO warehouse (name)
VALUES
('wh01'),
('wh02'),
('wh03');
INSERT INTO customerwarehouse (customerid, warehouseid)
VALUES
(1,1),
(2,1),
(2,2),
(3,1),
(3,2),
(3,3);
I would like to write a query to return the customer/warehouse data in the following format:
Customer WH1 WH2 WH3
CustA wh01
CustB wh01 wh02
CustC wh01 wh02 wh03
My attempt to do this returns null for all warehouses.
How can I construct my query to return the data in the required format?
In order to get the result, you will want to JOIN the tables and apply the PIVOT function. I would also suggest using the row_number() windowing function to get the number of warehouses for each customer - this will be the value that will be used as your new column headers.
select customername, wh1, wh2, wh3
from
(
select w.name warehousename,
c.name customername,
'wh'+cast(row_number() over(partition by c.id
order by w.id) as varchar(10)) seq
from customer c
inner join customerwarehouse cw
on c.id = cw.customerid
inner join warehouse w
on cw.warehouseid = w.id
) d
pivot
(
max(warehousename)
for seq in (wh1, wh2, wh3)
) piv;
See SQL Fiddle with Demo. If you have an unknown number of values, then you will need to use dynamic SQL to get the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME('wh'+cast(row_number() over(partition by customerid
order by warehouseid) as varchar(10)))
from customerwarehouse
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT customername, ' + #cols + '
from
(
select w.name warehousename,
c.name customername,
''wh''+cast(row_number() over(partition by c.id
order by w.id) as varchar(10)) seq
from customer c
inner join customerwarehouse cw
on c.id = cw.customerid
inner join warehouse w
on cw.warehouseid = w.id
) x
pivot
(
max(warehousename)
for seq in (' + #cols + ')
) p '
execute sp_executesql #query;
See SQL Fiddle with Demo. Both give a result:
| CUSTOMERNAME | WH1 | WH2 | WH3 |
| CustA | wh01 | (null) | (null) |
| CustB | wh01 | wh02 | (null) |
| CustC | wh01 | wh02 | wh03 |
Here's what I came up with after viewing the Complex PIVOT Example on this MSDN page:
SELECT
CustomerName,
case when [wh01] is null then null else 'wh01' end,
case when [wh02] is null then null else 'wh02' end,
case when [wh03] is null then null else 'wh03' end
FROM (
SELECT
c.Name AS CustomerName,
cw.id AS cwid,
w.name AS WarehouseName
FROM Customer c
JOIN CustomerWarehouse cw
ON c.id = cw.customerId
JOIN Warehouse w
ON w.id = cw.warehouseId
) AS SourceTable
pivot (
max(cwid)
FOR WarehouseName IN (
[wh01], [wh02], [wh03]
)
) AS PivotTable
On SQLFiddle: http://sqlfiddle.com/#!3/d5c60/42