sqlsql-serverunion-all

Replace Union All with joins or recursive CTE


Table A

ID Employee Name
1 Ashley
2 Sam
3 Samantha
4 Jessica
5 Tom

Table B

ID Week Salary
1 week 1 100
2 week 1 50
3 week 1 100
4 week 1 50
1 week 2 100
2 week 2 50
5 week 2 100
2 week 3 20
3 week 3 100
4 week 3 50
5 week 3 100

I want output as:

Table C

ID This Week This week Salary Next Week Next week Salary
1 week 1 100 week 2 100
2 week 1 50 week 2 50
3 week 1 100 Null
4 week 1 50 Null
5 Null week 2 100
1 week 2 100 Null
2 week 2 50 Week 3 20
3 Null Week 3 100
4 Null Week 3 50
5 Null Week 3 100
1 NULL Week 4 20
2 Week 3 20 Week 4 80
3 Week 3 100 Null
4 Week 3 50 Null
5 Week 3 100 Null

I have 14 weeks of data. In order to join 14 weeks of data I might need to do 14 union all. I am looking for an alternative to that

My attempt:

Select A.*, B.* from Table A
Left Outer join Table B      on A.Id = B.ID and B.week = Week 1
Left Outer join Table B AS C on A.Id = C.ID and C.week = Week 2
UNION ALL
Select * from Table A
Left Outer join Table B on A.Id = B.ID and week = Week 2
Left Outer join Table B AS C on A.Id = C.ID and C.week = Week 3

Solution

  • There's no need for a recursive CTE here, you can just make a dataset of your distinct weeks and employees. Ideally you should have a separate table for your weeks (if you don't I recommend doing so), but you can use a DISTINCT if not. I also assume your week column is really an int, not a varchar. If it isn't fix that design; week 2 is meant to be before week 10, but with a varchar it would be after, and your design is flawed.

    With all that, this gives a solution like thebelow:

    WITH EmployeeWeeks AS(
        SELECT DISTINCT
               E.EmployeeID,
               S.Week
        FROM dbo.Employee E
             CROSS JOIN dbo.Salary S)
    SELECT EW.EmployeeID,
           S.Week,
           S.Salary,
           LEAD(S.Week) OVER (PARTITION BY EW.EmployeeID ORDER BY EW.Week) AS NextWeek,
           LEAD(S.Salary) OVER (PARTITION BY EW.EmployeeID ORDER BY EW.Week) AS NextSalary
    FROM EmployeeWeeks EW
         LEFT JOIN dbo.Salary S ON EW.EmployeeID = S.EmployeeID
                               AND EW.Week = S.Week
    ORDER BY EW.[Week],
             EW.EmployeeID;
    

    db<>fiddle
    Note, that the sample data given by the OP has no data for week 4, so does not give the expected results in the fiddle, as it's impossible to give data for sample data we're missing.