Home > Enterprise >  SQL Code to forward-fill row values till next non-null rows in SQL Server
SQL Code to forward-fill row values till next non-null rows in SQL Server

Time:12-20

In the below table, the [MonthEndDate] has non-null values. Relative to this, from column [employeeId] till column [jobDescription] all null values should be forward-filled with data in the row 4 till row 16 and for last 2 columns i.e. [StaffTypeID] and [Description], all null values should be forward-filled with data in the row 1 till row 12 and similarly for the remaining rows.

Please use this db-fiddle link containing the required CREATE and INSERT statements to generate the table in problem statement.

Table 1 is table in Problem Statement and Table 2 is the desired output.

I would be appreciate if you could share the required SQL code.

Table 1

MonthEndDate employeeId last_day_jobeffectiveDate employeeType employeeStatus scheduledWorkHours supervisorId jobCode jobDescription StaffTypeID Description
05/31/2013 1 Accounting Assistant
06/30/2013
07/31/2013 E101 06/30/2013 INT A 80.0 C101 Intern - Consulting
08/31/2013 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting
09/30/2013
10/31/2013
11/30/2013
12/31/2013
01/31/2014
02/28/2014
03/31/2014
04/30/2014
05/31/2014 5 Consultant
06/30/2014
07/31/2014
08/31/2014
09/30/2014 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant
10/31/2014
11/30/2014
12/31/2014
01/31/2015
02/28/2015
03/31/2015
04/30/2015
05/31/2015

Table 2:

MonthEndDate employeeId last_day_jobeffectiveDate employeeType employeeStatus scheduledWorkHours supervisorId jobCode jobDescription StaffTypeID Description
05/31/2013 1 Accounting Assistant
06/30/2013 1 Accounting Assistant
07/31/2013 E101 06/30/2013 INT A 80.0 C101 Intern - Consulting 1 Accounting Assistant
08/31/2013 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
09/30/2013 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
10/31/2013 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
11/30/2013 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
12/31/2013 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
01/31/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
02/28/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
03/31/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
04/30/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 1 Accounting Assistant
05/31/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 5 Consultant
06/30/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 5 Consultant
07/31/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 5 Consultant
08/31/2014 E101 08/31/2013 INT T 80.0 C101 Intern - Consulting 5 Consultant
09/30/2014 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
10/31/2014 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
11/30/2014 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
12/31/2014 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
01/31/2015 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
02/28/2015 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
03/31/2015 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
04/30/2015 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant
05/31/2015 E101 09/30/2014 REG A 80.0 S101 C201 Staff Consultant 5 Consultant

CodePudding user response:

This shows only for the columns employeeId,last_day_jobeffectiveDate how you can do it.

It uses for every column the island and gaps algorithm

You of course have to complete it for the rest

You need to check the CASE WHENfor every column, as determins which cases should get then MAX values and which not

MERGE empworkhours AS tgt  
USING (SELECT
[MonthEndDate],
CASE WHEN
  ([employeeId] IS NULL 
  OR TRIM([employeeId]) = '')
    AND MAX([employeeId]) OVER(
                      ORDER BY MonthEndDate
                      ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) IS NOT NULL
  
  THEN 
  MAX([employeeId]) OVER(
                      ORDER BY MonthEndDate
                      ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
  ELSE [employeeId] END as [employeeId]
  ,CASE WHEN
  ([last_day_jobeffectiveDate] IS NULL 
  )
    AND MAX([last_day_jobeffectiveDate]) OVER(
                      ORDER BY MonthEndDate
                      ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING) IS NOT NULL
  
  THEN 
  MAX([last_day_jobeffectiveDate]) OVER(
                      ORDER BY MonthEndDate
                      ROWS BETWEEN UNBOUNDED PRECEDING AND 1 PRECEDING)
  ELSE [last_day_jobeffectiveDate] END as [last_day_jobeffectiveDate]
FROM [empworkhours]) as src ([MonthEndDate],employeeId,last_day_jobeffectiveDate)  
ON (tgt.[MonthEndDate] = src.[MonthEndDate])  
WHEN MATCHED AND tgt.last_day_jobeffectiveDate IS NULL  
    THEN UPDATE SET tgt.[employeeId] =  src.[employeeId],
                    tgt.[last_day_jobeffectiveDate] = src.[last_day_jobeffectiveDate];
Warning: Null value is eliminated by an aggregate or other SET operation.
22 rows affected
SELECT * FROM empworkhours
MonthEndDate employeeId last_day_jobeffectiveDate employeeType employeeStatus scheduledWorkHours supervisorId jobCode jobDescription StaffTypeID Description
2013-05-31                      null                       null                                           1 Accounting Assistant
2013-06-30                      null                       null                                           null
2013-07-31 E101 2013-06-30 INT A 80                      C101 Intern - Consulting null
2013-08-31 E101 2013-08-31 INT T 80                      C101 Intern - Consulting null
2013-09-30 E101 2013-08-31                       null                                           null
2013-10-31 E101 2013-08-31                       null                                           null
2013-11-30 E101 2013-08-31                       null                                           null
2013-12-31 E101 2013-08-31                       null                                           null
2014-01-31 E101 2013-08-31                       null                                           null
2014-02-28 E101 2013-08-31                       null                                           null
2014-03-31 E101 2013-08-31                       null                                           null
2014-04-30 E101 2013-08-31                       null                                           null
2014-05-31 E101 2013-08-31                       null                                           5 Consultant
2014-06-30 E101 2013-08-31                       null                                           null
2014-07-31 E101 2013-08-31                       null                                           null
2014-08-31 E101 2013-08-31                       null                                           null
2014-09-30 E101 2014-09-30 REG A 80 S101 C201 Staff Consultant null
2014-10-31 E101 2014-09-30                       null                                           null
2014-11-30 E101 2014-09-30                       null                                           null
2014-12-31 E101 2014-09-30                       null                                           null
2015-01-31 E101 2014-09-30                       null                                           null
2015-02-28 E101 2014-09-30                       null                                           null
2015-03-31 E101 2014-09-30                       null                                           null
2015-04-30 E101 2014-09-30                       null                                           null
2015-05-31 E101 2014-09-30                       null                                           null

fiddle

CodePudding user response:

I did this just a little differently as I did not use a merge and was also forced to use an additional CTE to fix the employeeStatus issue. I also put my data into a temp table, so you will have to change that in your fiddle. Something like this might work:

;WITH CTE AS
(
SELECT MonthEndDate, MAX(last_day_jobeffectiveDate) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) last_day_jobeffectiveDate ,
          MAX(employeeType) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) employeeType,
         MAX(EmployeeID) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) EmployeeID,
          MAX(scheduledWorkHours) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) scheduledWorkHours ,
          MAX(supervisorId) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) supervisorId ,
          MAX(JobCode) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) JobCode,
          MAX(JobDescription) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) JobDescription,
          MAX(StaffTypeID) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) StaffTypeID,
          MAX(Description) OVER(ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW) Description
         , t1.employeeStatus        
FROM #empworkhours t1
),CTE2 AS
(
    SELECT MonthEndDate,
            EmployeeID,
            last_day_jobeffectiveDate,
            employeeType, 
            MAX(employeeStatus) OVER( Partition by last_day_jobeffectiveDate ORDER BY MonthEndDate ROWS BETWEEN UNBOUNDED PRECEDING and CURRENT ROW ) employeeStatus,
            scheduledWorkHours,
            supervisorId,
            JobCode,
            JobDescription,
            StaffTypeID,
            Description
    FROM CTE
)

UPdATE #empworkhours
    SET employeeId = t2.EmployeeID
    , last_day_jobeffectiveDate = t2.last_day_jobeffectiveDate
    ,employeeType = t2.employeeType
    ,employeeStatus = t2.employeeStatus
    ,scheduledWorkHours = t2.scheduledWorkHours
    ,supervisorId = t2.supervisorId
    ,jobCode = t2.JobCode
    ,jobDescription = t2.JobDescription
    ,StaffTypeID = t2.StaffTypeID
    ,Description = t2.Description
FROM CTE2 t2
INNER JOIN #empworkhours t1 on t1.MonthEndDate = t2.MonthEndDate
  • Related