Struggling with a dynamic pivot on multiple columns with one being concatenated - sql-server

I have a table with data like so:
Employee PRDate Type Code Amount Subject Eligible
1234 1/1/2015 D 1 100.00 100.00 0.00
1234 1/1/2015 D 2 200.00 0.00 0.00
5678 1/1/2015 D 1 500.00 40.00 500.00
1234 1/1/2015 E 1 300.00 30.00 300.00
5678 1/1/2015 E 1 700.00 700.00 500.00
1234 1/1/2015 E 2 400.00 200.00 0.00
1234 1/8/2015 L 55 40.00 40.00 40.00
And I need for the data to be displayed like this:
Employee PRDate D1Amt D1Subj D1Elig D2Amt D2Subj D2Elig E1Amt E1Subj E1Elig E2Amt E2Subj E2Elig L55Amt L55Subj L55Elig
1234 1/1/2015 100.00 100.00 0.00 200.00 0.00 0.00 300.00 30.00 300.00 400.00 200.00 0.00 40.00 40.00 40.00
4678 1/1/2015 500.00 40.00 500.00 700.00 700.00 500.00
I can pivot on one column but when I try combining the Type and Code columns to get the one I get conversion errors (Type is a varchar and code is a tinyint). I'm not sure how to get to the desired results other than dynamic pivot. Can the desired results be achieved?
I've gotten this far but I can't figure out how to combine the type, code and each money columns (amount, subject and eligible) to get the data under the correct columns.
IF EXISTS (
SELECT *
FROM sys.tables
WHERE name LIKE '#temp285865%')
DROP TABLE #temp285865;
Create table dbo.#temp285865
(
EDLCodetemp varchar(10)
);
INSERT INTO #temp285865
(
[EDLCodetemp]
)
SELECT DISTINCT EDLCode
FROM #results
ORDER BY EDLCode;
-- Building a comma separated list of EDLCodes in #edltemp
DECLARE #cols varchar(1000);
SELECT #cols = COALESCE(#cols + ',[' + [EDLCodetemp] + ']', '[' + [EDLCodetemp] + ']')
FROM #temp285865;
-- Building the query appending columns
DECLARE #query varchar(4000);
SET #query =
'SELECT [CoName],
[PRCo],
[PRGroup],
[PREndDate],
[PaySeq],
[EDLType],
[Hours],
[SubjectAmt],
[EligibleAmt],
[PaidMth],
[LastName],
[FirstName],
[UseOver],
[OverAmt],
[Amount],
[PRGRDescrip],
[LimitPeriod],
[LimitMth],
[PREHEmployee],
[SortName],
[PaybackAmt],
[PaybackOverAmt],
[PaybackOverYN],
[PRDTEmployee],
[TrueEarns], '
+ #cols + ' FROM
(
SELECT [CoName],
[PRCo],
[PRGroup],
[PREndDate],
[PaySeq],
[EDLType],
[Hours],
[SubjectAmt],
[EligibleAmt],
[PaidMth],
[LastName],
[FirstName],
[PRDLDescrip],
[PRECDescrip],
[UseOver],
[OverAmt],
[Amount],
[PRGRDescrip],
[LimitPeriod],
[LimitMth],
[PREHEmployee],
[SortName],
[PaybackAmt],
[PaybackOverAmt],
[PaybackOverYN],
[PRDTEmployee],
[TrueEarns],
[EDLCode]
FROM #results
) p
PIVOT (
MAX(EDLCode)
FOR [EDLCode] IN (' + #cols + ')
)
as pvt';
EXEC(#query);
DROP TABLE #temp285865;

The following PIVOT with dynamic SQL would give you the result you want, based on the input data you provided (I changed the PRDate in the last row though).
The first statement builds an intermediate table #bt with the column names you want and the associated value. Then the column names are built in #cols for the dynamic SQL statement. Finally the intermediate table #bt is pivoted with a dynamic SQL statement using the #cols to pivot.
SET NOCOUNT ON;
CREATE TABLE #t(
Employee INT,
PRDate DATETIME,
Type CHAR(1),
Code TINYINT,
Amount DECIMAL(28,2),
Subject DECIMAL(28,2),
Eligible DECIMAL(28,2)
);
INSERT INTO #t(Employee,PRDate,Type,Code,Amount,Subject,Eligible)VALUES(1234,'2015-01-01','D',1,100.00,100.00,0.00);
INSERT INTO #t(Employee,PRDate,Type,Code,Amount,Subject,Eligible)VALUES(1234,'2015-01-01','D',2,200.00,0.00,0.00);
INSERT INTO #t(Employee,PRDate,Type,Code,Amount,Subject,Eligible)VALUES(5678,'2015-01-01','D',1,500.00,40.00,500.00);
INSERT INTO #t(Employee,PRDate,Type,Code,Amount,Subject,Eligible)VALUES(1234,'2015-01-01','E',1,300.00,30.00,300.00);
INSERT INTO #t(Employee,PRDate,Type,Code,Amount,Subject,Eligible)VALUES(5678,'2015-01-01','E',1,700.00,700.00,500.00);
INSERT INTO #t(Employee,PRDate,Type,Code,Amount,Subject,Eligible)VALUES(1234,'2015-01-01','E',2,400.00,200.00,0.00);
INSERT INTO #t(Employee,PRDate,Type,Code,Amount,Subject,Eligible)VALUES(1234,'2015-01-01','L',55,40.00,40.00,40.00);
SELECT
Employee,
PRDate,
Type+CAST(Code AS VARCHAR(3))+ca.name AS colname,
ca.val
INTO
#bt
FROM
#t
CROSS APPLY(
SELECT Amount AS val,'Amt' AS name
UNION ALL
SELECT Subject AS val,'Subj' AS name
UNION ALL
SELECT Eligible AS val,'Elig' AS name
) AS ca;
/* If you need to SUM for all dates, instead use this statement to create #bt
SELECT
Employee,
Type+CAST(Code AS VARCHAR(3))+ca.name AS colname,
ca.val
INTO
#bt
FROM
(
SELECT
Employee,
Type,
Code,
SUM(Amount) AS Amount,
SUM(Subject) AS Subject,
SUM(Eligible) AS Eligible
FROM
#t
GROUP BY
Employee,
Type,
Code
) AS t
CROSS APPLY(
SELECT Amount AS val,'Amt' AS name
UNION ALL
SELECT Subject AS val,'Subj' AS name
UNION ALL
SELECT Eligible AS val,'Elig' AS name
) AS ca;
*/
DECLARE #cols VARCHAR(8000);
SET #cols=STUFF(
(SELECT DISTINCT
',['+colname+']'
FROM
#bt
FOR XML PATH('')),
1,
1,
''
);
DECLARE #sql VARCHAR(MAX);
SET #sql='
SELECT
*
FROM
#bt
PIVOT(
MAX(val)
FOR colname IN ('+#cols+')
) AS piv
';
EXEC (#sql);
DROP TABLE #bt;
DROP TABLE #t;
The result is the following:
Employee PRDate D1Amt D1Elig D1Subj D2Amt D2Elig D2Subj E1Amt E1Elig E1Subj E2Amt E2Elig E2Subj L55Amt L55Elig L55Subj
1234 2015-01-01 100.00 0.00 100.00 200.00 0.00 0.00 300.00 300.00 30.00 400.00 0.00 200.00 40.00 40.00 40.00
5678 2015-01-01 500.00 500.00 40.00 NULL NULL NULL 700.00 500.00 700.00 NULL NULL NULL NULL NULL NULL

Related

How to delete if the data for the days following each other are the same - T-SQL

I have a table like this;
OwnerName
Date
Value1
Value2
Value3
Jack
2020-01-01
5.5
500
22.76
Jack
2020-01-02
4.7
650
33.75
Jack
2020-01-03
4.7
650
33.75
Jack
2020-01-04
4.7
650
33.75
Jack
2020-01-05
5.1
780
35.50
Jack
2020-01-06
6.8
340
20.75
Jack
2020-01-07
9.2
450
15.50
Jack
2020-01-08
9.2
450
15.50
Jack
2020-01-09
9.2
450
15.50
Jack
2020-01-10
9.2
450
15.50
If Value 1, Value 2, and Value 3 are the same for consecutive dates, how can I delete dates other than the earliest date from those dates?
According to this sample table, after the delete query, the table should be as follows;
OwnerName
Date
Value1
Value2
Value3
Jack
2020-01-01
5.5
500
22.76
Jack
2020-01-02
4.7
650
33.75
Jack
2020-01-05
5.1
780
35.50
Jack
2020-01-06
6.8
340
20.75
Jack
2020-01-07
9.2
450
15.50
Table Script :
CREATE TABLE OwnerRateInfo(
OwnerName NVARCHAR(20) NOT NULL
,Date DATE NOT NULL
,Value1 DECIMAL(20,1) NOT NULL
,Value2 DECIMAL(20,0) NOT NULL
,Value3 DECIMAL(20,2) NOT NULL
,PRIMARY KEY(OwnerName,Date)
);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-01',5.5,500,22.76);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-02',4.7,650,33.75);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-03',4.7,650,33.75);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-04',4.7,650,33.75);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-05',5.1,780,35.50);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-06',6.8,340,20.75);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-07',9.2,450,15.50);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-08',9.2,450,15.50);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-09',9.2,450,15.50);
INSERT INTO OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) VALUES (N'Jack','2020-01-10',9.2,450,15.50);
Thanks in advance
I would solve this using a longwinded CASE LAG() statement to align records for deletion. The lag marks preceding records with duplicate values = 1. Joining that dataset with a delete statement will produce the desired result.
DELETE D FROM
OwnerRateInfo D
INNER JOIN
(
SELECT OwnerName, Date,
IsOneDayApartAndSameValues = CASE WHEN ABS(DATEDIFF(DAY,LAG(Date) OVER(PARTITION BY OwnerName,Value1,Value2,Value3 ORDER BY Date),Date)) = 1 THEN 1 ELSE 0 END
FROM OwnerRateInfo
)AS K ON K.OwnerName = D.OwnerName AND K.Date=D.Date AND K.IsOneDayApartAndSameValues = 1
SELECT * FROM OwnerRateInfo
Output
OwnerName Date Value1 Value2 Value3
Jack 2020-01-01 5.5 500 22.76
Jack 2020-01-02 4.7 650 33.75
Jack 2020-01-05 5.1 780 35.50
Jack 2020-01-06 6.8 340 20.75
Jack 2020-01-07 9.2 450 15.50
This should give you a start:
-- Sample data.
declare #OwnerRateInfo as Table(
OwnerName NVARCHAR(20) NOT NULL
,Date DATE NOT NULL
,Value1 DECIMAL(20,1) NOT NULL
,Value2 DECIMAL(20,0) NOT NULL
,Value3 DECIMAL(20,2) NOT NULL );
insert into #OwnerRateInfo(OwnerName,Date,Value1,Value2,Value3) values
(N'Jack','2020-01-01',5.5,500,22.76),
(N'Jack','2020-01-02',4.7,650,33.75),
(N'Jack','2020-01-03',4.7,650,33.75),
(N'Jack','2020-01-04',4.7,650,33.75),
(N'Jack','2020-01-05',5.1,780,35.50),
(N'Jack','2020-01-06',6.8,340,20.75),
(N'Jack','2020-01-07',9.2,450,15.50),
(N'Jack','2020-01-08',9.2,450,15.50),
(N'Jack','2020-01-09',9.2,450,15.50),
(N'Jack','2020-01-10',9.2,450,15.50);
select * from #OwnerRateInfo;
-- Number rows having the same OwnerName , Value1 , Value2 and Value3 by ascending Date .
select OwnerName, [Date], Value1, Value2, Value3,
Row_Number() over ( partition by OwnerName, Value1, Value2, Value3 order by [Date] ) as RN
from #OwnerRateInfo;
-- Delete the undesirable rows.
-- The syntax to delete from a join is a bit peculiar, but such is life.
delete from #OwnerRateInfo
from #OwnerRateInfo as ORI inner join (
-- Get the numbered rows as shown in the previous example.
select OwnerName, [Date], Value1, Value2, Value3,
Row_Number() over ( partition by OwnerName, Value1, Value2, Value3 order by [Date] ) as RN
from #OwnerRateInfo
) as ORIT
on ORI.OwnerName = ORIT.OwnerName and ORI.[Date] = ORIT.[Date] and
ORI.Value1 = ORIT.Value1 and ORI.Value2 = ORIT.Value2 and ORI.Value3 = ORIT.Value3 and
ORIT.RN > 1; -- Keep the first match for each partition and delete the rest.
-- Display the result.
select * from #OwnerRateInfo;

How to get only a distinct row

I have a table which is shown on below
id locale roaming rent
301 NULL 18.00 NULL
300 NULL NULL 5.00
299 11.00 NULL NULL
298 NULL NULL 4.00
297 NULL 20.00 NULL
296 NULL NULL 6.00
295 9.00 NULL NULL
294 NULL 20.00 NULL
293 10.00 NULL NULL
I want to get only one value in each column (without id column) in a row. How can I do it? BUT I want to do it only in one select query.
A possible solution:
SELECT (
SELECT TOP 1 [local]
FROM tbl
WHERE [local] IS NOT NULL
ORDER BY [id] DESC
) AS [local]
,(
SELECT TOP 1 [roaming]
FROM tbl
WHERE [roaming] IS NOT NULL
ORDER BY [id] DESC
) AS [roaming]
,(
SELECT TOP 1 [rent]
FROM tbl
WHERE [rent] IS NOT NULL
ORDER BY [id] DESC
) AS [rent]
I do it so
DECLARE #locale AS DECIMAL(11,2)
DECLARE #roaming AS DECIMAL(11,2)
DECLARE #rent AS DECIMAL(11,2)
SELECT #locale=COALESCE(locale, #locale), #roaming=COALESCE(roaming, #roaming), #rent=COALESCE(rent, #rent) FROM my_table
SELECT #locale as locale, #roaming as roaming, #rent as rent

How To Pivot table using SQL server

i creating SQL table its have three column fields
NAME TYPE Amount
RAJ 401K % 500
Kumar ROTH 600
RAJ 401K % 500
Kumar ROTH 700
Karthi 401K % 1500
RAj Roth 800
Tony DPD 8
above table i have three column Fields Name and Type finally Amount. i try convert this table like separate columns Type. in my table Raj come in table many time so i want to sum Raj all value which values come with 401K table finally its show single value. its added 401k value. Roth value seperate like this
Name 401k% Roth Amount
Raj 1000 800 1800
Kumar 0 1300 1300
Karthi 1500 0 1500.
Nimi 0 0 0 -- this is should Remove only value come with only 401k% and Roth . other value should be delete .
i want like this. i am trying to achive this using Pivot talbe i am getting Null value
select [Name],[401k%] ,[Roth%]
from DeductionHistory
PIVOT
( SUM(Amount) FOR DeductionName IN([401k%],[Roth%])
)
AS Pivottable
please any one help me . how to get value Like this
CREATE TABLE #TABLE111
([NAME] VARCHAR(6), [TYPE] VARCHAR(6), [AMOUNT] INT)
INSERT INTO #TABLE111
([NAME], [TYPE], [AMOUNT])
VALUES
('RAJ', '401K %', 500),
('KUMAR', 'ROTH', 600),
('RAJ', '401K %', 500),
('KUMAR', 'ROTH', 700),
('KARTHI', '401K %', 1500),
('RAJ', 'ROTH', 800)
SELECT NAME ,ISNULL([401K %],0) [401K %] ,ISNULL([ROTH],0) [ROTH] ,ISNULL([401K %],0)+ISNULL([ROTH],0) 'TOTAL'
FROM
(
SELECT *
FROM #TABLE111
) SRC
PIVOT
(
SUM([AMOUNT])
FOR [TYPE] IN ([401K %], [ROTH] )
) PIV
ORDER BY NAME DESC
output
NAME 401K % ROTH TOTAL
RAJ 1000 800 1800
Kumar 0 1300 1300
Karthi 1500 0 1500
--I have included DPD the query
DECLARE #DeductionHistory TABLE (NAME VARCHAR(20), [TYPE] VARCHAR(20),Amount MONEY)
INSERT INTO #DeductionHistory VALUES
('RAJ','401K%',500),
('Kumar','ROTH',600),
('RAJ','401K%',500),
('Kumar','ROTH',700),
('Karthi','401K%',1500),
('RAj','ROTH',800),
('Tony' ,'DPD', 8)
/*****Use a VTE or temp table*****/
;WITH DeductionHistory
AS(
SELECT * FROM #DeductionHistory
PIVOT
(
SUM(Amount) FOR [TYPE] IN ([401K%],[ROTH],[DPD])
) PV1
)
SELECT
[NAME]
,ISNULL([401K%],0) AS [401K%]
,ISNULL([ROTH],0) AS [ROTH]
,ISNULL([DPD],0) AS [DPD]
,ISNULL([401K%],0)+ISNULL([ROTH],0)+ISNULL([DPD],0) AS Amount
FROM DeductionHistory
OUTPUT
NAME 401K% ROTH DPD Amount
Karthi 1500.00 0.00 0.00 1500.00
Kumar 0.00 1300.00 0.00 1300.00
RAJ 1000.00 800.00 0.00 1800.00
Tony 0.00 0.00 8.00 8.00

SQL Server : pivot or not to pivot

I have a table in which I run a select statement and returns the following data
Name date skill seconds calls
----------------------------------------------
bob 9/2/2016 706 12771 56
bob 9/2/2016 707 4061 16
bob 9/2/2016 708 2577 15
bob 9/2/2016 709 2156 6
I want to return like below one row of data:
Name date 706sec 706call 707sec 707call 708sec 708call 709sec 709call
----------------------------------------------------------------------------------
bob 9/2/2016 12771 56 4061 16 2577 15 2156 6
My first attempt was a pivot but does not return a single row:
Select
name, date, seconds, calls, [706], [707],[708],[709],
from
(Select
name, date, skill, seconds, calls
From
tablecalls
Where
date between '09/02/2016 00:00' and '09/02/2016 23:59'
and name = 'bob') as b
pivot
(sum(seconds) for skill in ([706], [707], [708], [709] )) as p1
This returns:
name date calls 706sec 707sec 708sec 709sec
---------------------------------------------------------
bob 9/2/2016 6 NULL NULL NULL 2156
bob 9/2/2016 15 NULL NULL 2577 NULL
bob 9/2/2016 16 NULL 4061 NULL NULL
bob 9/2/2016 56 12771 NULL NULL NULL
Maybe PIVOT is not the right way to do this. Is there another way?
can you format your data in question. I am not sure whether I get youe point?
CREATE TABLE #tt([name] VARCHAR(10),[date] DATE,skill INT,seconds INT, calls int )
INSERT INTO #tt
SELECT 'bob','9/2/2016',706,12771,56 UNION all
SELECT 'bob','9/2/2016',707,4061,16 UNION all
SELECT 'bob','9/2/2016',708,2577,15 UNION all
SELECT 'bob','9/2/2016',709,2156,6
SELECT * FROM (
SELECT t.name,t.date,c.* FROM #tt AS t
CROSS APPLY(VALUES(LTRIM(t.skill)+'sec',t.seconds),(LTRIM(t.skill)+'calls',t.seconds)) c(t,v)
) AS A
PIVOT(MAX(v) FOR t IN ([706sec],[706calls],[707sec],[707calls],[708sec],[708calls],[709sec],[709calls])) p
name date 706sec 706calls 707sec 707calls 708sec 708calls 709sec 709calls
---------- ---------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
bob 2016-09-02 12771 12771 4061 4061 2577 2577 2156 2156
if the count of skill is not fix, you can use dynamic script:
DECLARE #col VARCHAR(max),#sql VARCHAR(max)
SELECT #col=ISNULL(#col+',[','[')+LTRIM(skill)+'sec],['+LTRIM(skill)+'calls]' FROM #tt GROUP BY skill
SET #sql='
SELECT * FROM (
SELECT t.name,t.date,c.* FROM #tt AS t
CROSS APPLY(VALUES(LTRIM(t.skill)+''sec'',t.seconds),(LTRIM(t.skill)+''calls'',t.seconds)) c(t,v)
) AS A
PIVOT(MAX(v) FOR t IN ('+#col+')) p'
EXEC (#sql)

Dynamic pivot multiple columns

I have a table with results like this:
EMP_ID | Boss_ID | Boss_Name | Specialty
1001 001 John sql
1001 001 John c#
1002 002 James c++
1002 003 Sarah sql
1002 003 Sarah python
1003 004 Jesse networking
Employees can have multiple bosses which can have multiple specialties.
I need to dynamically pivot the data so that I have one line per employee. I need to display the employee, all the bosses they have and just their line 1 specialty.
I am able to use dynamic pivot and display the multiple bosses part but I am unsure of how to display their specialty next to their name.
Here is what I have:
DECLARE #cols AS NVARCHAR(max)
,#query AS NVARCHAR(max)
select t.EMP_ID
,t.Boss_Name
,t.Boss_ID
,t.Specialty
,'BOSS' + '_' + cast(ROW_NUMBER() OVER (PARTITION BY t.EMP_ID ORDER BY t.BOSS_ID asc) AS VARCHAR) AS b_rn
,'SPEC' + '_' + cast(ROW_NUMBER() OVER (PARTITION BY t.Specialty ORDER BY t.BOSS_ID asc) AS VARCHAR) AS spec_rn
INTO #work
from #testing t
SELECT #cols = STUFF(
(SELECT DISTINCT TOP 100 PERCENT '],[' + w.b_rn
FROM #work w
ORDER BY '],[' + w.b_rn
FOR XML PATH('')
), 1, 2, ''
) + ']'
PRINT #cols
SET #query = N' SELECT EMP_ID,' + #cols + N'
INTO ##work_results FROM
(
SELECT EMP_ID
,Boss_Name
,b_rn
FROM #work
) AS sourcetable
PIVOT
(
max(Boss_Name) for b_rn IN ('+ #cols + N')
) AS pivot_table'
execute(#query)
select * from ##work_results
This gives me:
EMP_ID | BOSS_1 | BOSS_2 | BOSS_3
1001 John John NULL
1002 James Sarah Sarah
1003 Jesse NULL NULL
What I am really looking for is results like this:
EMP_ID | Boss_1 | Specialty_1 | Boss_2 | Specialty_1
1001 John sql
1002 James c++ Sarah sql
1003 Jesse networking
I have looked at other posts but they aren't quite what I am looking for.
Any help would be wonderful.
Thanks!
You might go this way:
The trick is, to concatenate your values. Therefore only one column, no problem with pivot...
DECLARE #tbl TABLE(EMP_ID INT,Boss_ID INT,Boss_Name VARCHAR(100),Specialty VARCHAR(100));
INSERT INTO #tbl VALUES
(1001,001,'John','sql')
,(1001,001,'John','c#')
,(1002,002,'James','c++')
,(1002,003,'Sarah','sql')
,(1002,003,'Sarah','python')
,(1003,004,'Jesse','networking');
SELECT p.*
FROM
(
SELECT tbl.EMP_ID
--If you need your Bosses in the given order you must add a sort crit to your original table!
,'Column_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.EMP_ID ORDER BY tbl.EMP_ID) AS VARCHAR(MAX)) AS ColumnName
,tbl.Boss_Name + ' (' + tbl.Specialty + ')' AS Concatenated
FROM #tbl AS tbl
) AS ToBePivoted
PIVOT
(
MIN(Concatenated) FOR ColumnName IN(Column_1,Column_2,Column_3 /*add maximum here*/)
) As p
The result
1001 John (sql) John (c#) NULL
1002 James (c++) Sarah (sql) Sarah (python)
1003 Jesse (networking) NULL NULL
If you need the values separated another trick is, to concatenate all needed columns in XML-format (but not XML-Type!).
As the concatenation is XML-Format it is quite easy to extract the elements just via their index.
DECLARE #tbl TABLE(EMP_ID INT,Boss_ID INT,Boss_Name VARCHAR(100),Specialty VARCHAR(100));
INSERT INTO #tbl VALUES
(1001,001,'John','sql')
,(1001,001,'John','c#')
,(1002,002,'James','c++')
,(1002,003,'Sarah','sql')
,(1002,003,'Sarah','python')
,(1003,004,'Jesse','networking');
SELECT p.EMP_ID
,CAST(Column_1 AS XML).value('x[1]','int') AS BossID_1
,CAST(Column_1 AS XML).value('x[2]','varchar(max)') AS BossName_1
,CAST(Column_1 AS XML).value('x[3]','varchar(max)') AS specialty_1
,CAST(Column_2 AS XML).value('x[1]','int') AS BossID_2
,CAST(Column_2 AS XML).value('x[2]','varchar(max)') AS BossName_2
,CAST(Column_2 AS XML).value('x[3]','varchar(max)') AS specialty_2
,CAST(Column_3 AS XML).value('x[1]','int') AS BossID_3
,CAST(Column_3 AS XML).value('x[2]','varchar(max)') AS BossName_3
,CAST(Column_3 AS XML).value('x[3]','varchar(max)') AS specialty_3
/*Add a maximum here*/
FROM
(
SELECT tbl.EMP_ID
--If you need your Bosses in the given order you must add a sort crit to your original table!
,'Column_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.EMP_ID ORDER BY tbl.EMP_ID) AS VARCHAR(MAX)) AS ColumnName
,'<x>' + CAST(tbl.Boss_ID AS VARCHAR(10)) + '</x><x>' + tbl.Boss_Name + '</x><x>' + tbl.Specialty + '</x>' AS ValuesAsXML
FROM #tbl AS tbl
) AS ToBePivoted
PIVOT
(
MIN(ValuesAsXML) FOR ColumnName IN(Column_1,Column_2,Column_3 /*add maximum here*/)
) As p
The result
1001 1 John sql 1 John c# NULL NULL NULL
1002 2 James c++ 3 Sarah sql 3 Sarah python
1003 4 Jesse networking NULL NULL NULL NULL NULL NULL

Resources