Reputation: 2186
Code (Sample Data Staging):
DECLARE @Emp TABLE
(
[EId] INT IDENTITY(1, 1)
, [FN] NVARCHAR(50)
, [LN] NVARCHAR(50)
) ;
DECLARE @EmpPhCont TABLE
(
[EId] INT
, [PhType] VARCHAR(10)
, [PhNum] VARCHAR(16)
, [PhExt] VARCHAR(10)
, [IsMain] BIT
, [CreatedOn] DATETIME
) ;
INSERT INTO @Emp
VALUES
( N'Emp1', N'Emp1' )
, ( N'Emp2', N'Emp2' )
, ( N'Emp3', N'Emp3' )
, ( N'Emp4', N'Emp4' )
, ( N'Emp5', N'Emp5' )
, ( N'Emp6', N'Emp5' ) ;
INSERT INTO @EmpPhCont
VALUES
( 1, 'Home', '111111111', NULL, 0, '2020-01-01 00:00:01' )
, ( 1, 'Mobile', '222222222', NULL, 1, '2020-01-01 00:00:02' )
, ( 1, 'Work', '333333333', NULL, 0, '2020-01-01 00:00:03' )
, ( 2, 'Work', '444444444', '567', 1, '2020-01-01 00:00:04' )
, ( 2, 'Mobile', '555555555', NULL, 0, '2020-01-01 00:00:05' )
, ( 2, 'Mobile', '454545454', NULL, 0, '2020-01-01 00:00:06' )
, ( 3, 'Home', '777777777', NULL, 0, '2020-01-01 00:00:07' )
, ( 3, 'Mobile', '888888888', NULL, 1, '2020-01-01 00:00:08' )
, ( 3, 'Mobile', '12121212', NULL, 0, '2020-01-01 00:00:09' )
, ( 4, 'Work', '101010101', '111', 1, '2020-01-01 00:00:10' )
, ( 4, 'Work', '101010102', '232', 0, '2020-01-01 00:00:11' )
, ( 5, 'Work', '545454545', '456', 0, '2020-01-01 00:00:10' )
, ( 5, 'Work', '456456456', NULL, 1, '2020-01-01 00:00:11' ) ;
Description:
@Emp is the sample Employee table (Unique Employee records).
@EmpPhCont is the sample Employee Phone Contact table (Each Emp from @Emp table can have zero, one, or multiple phone numbers here - unique by Emp/Type).
Goal:
To output 1 record per employee with the following Columns
EId | HomeNum | MobileNum | WorkNum | WorkNumExt | MainPhType
Rules:
Return all EId for all records from @Emp, whether they have a @EmpPhCont record or not.
For each emp that has @EmpPhCont record avail, return the newest created PhNum and PhExt for the corresponding PhType, UNLESS an older record for the same Emp/PhType is marked as IsMain = 1 (For any emp, for whichever PhType, if IsMain = 1, always return that PhNum and PhExt value).
Expected Output:
EId HomeNum MobileNum WorkNum WorkNumExt MainPhType
1 111111111 222222222 333333333 NULL Mobile
2 NULL 454545454 444444444 567 Work
3 777777777 888888888 NULL NULL Mobile
4 NULL NULL 101010102 111 Work
5 NULL NULL 456456456 NULL Work
6 NULL NULL NULL NULL NULL
My unsuccessful try:
SELECT [EM].[EId]
, MAX ( IIF([PH].[PhType] = 'Home', [PH].[PhNum], NULL)) AS [HomePhNum]
, MAX ( IIF([PH].[PhType] = 'Mobile', [PH].[PhNum], NULL)) AS [MobilePhNum]
, MAX ( IIF([PH].[PhType] = 'Work', [PH].[PhNum], NULL)) AS [WorkPhNum]
FROM @Emp AS [EM]
LEFT JOIN @EmpPhCont AS [PH]
ON [EM].[EId] = [PH].[EId]
GROUP BY [EM].[EId] ;
Upvotes: 2
Views: 67
Reputation: 6798
row_number(), outer apply and aggregation:
select *
from @Emp as e
outer apply
(
select
MAX ( case when d.[PhType] = 'Home' then d.[PhNum] end) AS [HomePhNum]
, MAX ( case when d.[PhType] = 'Mobile' then d.[PhNum] end) AS [MobilePhNum]
, MAX ( case when d.[PhType] = 'Work' then d.[PhNum] end) AS [WorkPhNum]
, MAX ( case when d.[PhType] = 'Work' then d.[PhExt] end) AS [WorkNumExt]
, MAX ( case when IsMain = 1 then d.[PhType] end) AS MainPhType --work is max if both mob&work as set as main..
from
(
select *, row_number() over(partition by PhType order by IsMain DESC, CreatedOn DESC) as rownum
from @EmpPhCont as p
where p.EId = e.EId
) as d
where d.rownum = 1
) as ph;
Upvotes: 1
Reputation: 164139
Use ROW_NUMBER()
window function inside a CTE
to get the rows from @EmpPhCont
that you want returned and join this CTE
to @Emp
:
with cte as (
select *,
row_number() over (partition by [EId], [PhType] order by [IsMain] desc, [CreatedOn] desc) rn
from @EmpPhCont
)
select e.[EId],
max(case when c.[PhType] = 'Home' then c.[PhNum] end) HomeNum,
max(case when c.[PhType] = 'Mobile' then c.[PhNum] end) MobileNum,
max(case when c.[PhType] = 'Work' then c.[PhNum] end) WorkNum,
max(case when c.[PhType] = 'Work' then c.[PhExt] end) WorkNumExt,
max(case when c.[IsMain] = 1 then c.[PhType] end) MainPhType
from @Emp e left join cte c
on c.[EId] = e.[EId] and c.rn = 1
group by e.[EId]
See the demo.
Results:
> EId | HomeNum | MobileNum | WorkNum | WorkNumExt | MainPhType
> --: | :-------- | :-------- | :-------- | :--------- | :---------
> 1 | 111111111 | 222222222 | 333333333 | null | Mobile
> 2 | null | 454545454 | 444444444 | 567 | Work
> 3 | 777777777 | 888888888 | null | null | Mobile
> 4 | null | null | 101010101 | 111 | Work
> 5 | null | null | 456456456 | null | Work
> 6 | null | null | null | null | null
Upvotes: 3
Reputation: 159135
I would implement that using APPLY
:
SELECT EId, HomeNum, MobileNum, WorkNum, WorkNumExt
, COALESCE(HomeMain, MobileMain, WorkMain) AS MainPhType
FROM Emp e
OUTER APPLY (
SELECT TOP 1 c.[PhNum] AS HomeNum
, CASE WHEN c.[IsMain] = 1 THEN 'Home' END AS HomeMain
FROM EmpPhCont c
WHERE c.[EId] = e.[EId]
AND c.[PhType] = 'Home'
ORDER BY c.[IsMain] DESC, c.[CreatedOn] DESC
) home
OUTER APPLY (
SELECT TOP 1 c.[PhNum] AS MobileNum
, CASE WHEN c.[IsMain] = 1 THEN 'Mobile' END AS MobileMain
FROM EmpPhCont c
WHERE c.[EId] = e.[EId]
AND c.[PhType] = 'Mobile'
ORDER BY c.[IsMain] DESC, c.[CreatedOn] DESC
) mobile
OUTER APPLY (
SELECT TOP 1 c.[PhNum] AS WorkNum
, c.[PhExt] AS WorkNumExt
, CASE WHEN c.[IsMain] = 1 THEN 'Work' END AS WorkMain
FROM EmpPhCont c
WHERE c.[EId] = e.[EId]
AND c.[PhType] = 'Work'
ORDER BY c.[IsMain] DESC, c.[CreatedOn] DESC
) work
See SQL Fiddle for demo.
Output
EId | HomeNum | MobileNum | WorkNum | WorkNumExt | MainPhType
1 | 111111111 | 222222222 | 333333333 | (null) | Mobile
2 | (null) | 454545454 | 444444444 | 567 | Work
3 | 777777777 | 888888888 | (null) | (null) | Mobile
4 | (null) | (null) | 101010101 | 111 | Work
5 | (null) | (null) | 456456456 | (null) | Work
6 | (null) | (null) | (null) | (null) | (null)
Note: This solution will only be viable for large data sets if the EmpPhCont
table has an index on [EId], [PhType]
, otherwise it'll be too slow.
Upvotes: 1