Access 2010 - query showing running total for multiple records, dropping old record and adding new record on each line

StackOverflow https://stackoverflow.com/questions/15553928

Pergunta

I have an Access database which is tracking hours used by each employee in each pay period.

I need a query that will allow me to look back in time and see what the total was for just the last 25 pay periods, as calculated from each of the previous 26 pay periods, for each employee. This a rolling total in which, essentially, records that are 26 pay periods (or more) older must be ignored on a per-line basis. I have five years' worth of records, and it is unfortunately necessary to retain them all, and it is very important to be able to see what the 26-pay-period running total for each employee was, together with the hours used in a particular pay period.

Basically, we're looking at 51 records total for each employee - the first pay period the query actually shows, however, is 26 pay periods ago; it has a running total based on what happened in that pay period plus the previous 25.

Tables:
HoursID, EmployeeID, PayPeriodID, HoursUsed
PayPeriodID, PayPeriodEndDate

Query Results (already working):
EmployeeID, TotalOfHoursUsedLast26PP (this query requests a date to count back from)

Query Results I Need:
EmployeeID, PayPeriodID, HoursUsed, [Total Hours Used, Based on the 25 PP immediately previous to this PP]

I've been messing around with DSum, but I can't figure out how to make it only count the last 26 PP, counting the PPs I need, for one employee at a time, for each pay period separately.

To be clear: I need to be able to look back and run this query for 26 pay periods in 2009 or something; in Excel, for one individual employee, we did something that looks like this:

Line32_HoursUsedLast26PP = Line32_HoursUsedThisPP + Line31_HoursUsedLast26PP - Line4_HoursUsedThisPP

The results are something like:

2011-5 - 338.8
2011-6 - 398.5
2011-7 - 428.7
2011-8 - 442.5
2011-9 - 451
2011-10 - 451
2011-11 - 451
2011-12 - 451
2011-13 - 451
2011-14 - 451
2011-15 - 451
2011-16 - 452.4
2011-17 - 453.1
2011-18 - 454.3
2011-19 - 454.3
2011-20 - 455
2011-21 - 456.1
2011-22 - 460.2
2011-23 - 480
2011-24 - 480
2011-25 - 480
2011-26 - 480
2012-01 - 453.2
2012-02 - 381.2
2012-03 - 301.2
2012-04 - 221.2
2012-05 - 141.2
2012-06 - 81.5
2012-07 - 51.3
2012-08 - 37.5
2012-09 - 29
2012-10 - 29
2012-11 - 29
2012-12 - 29
2012-13 - 29
2012-14 - 29
2012-15 - 29
2012-16 - 27.6
2012-17 - 26.9
2012-18 - 25.7
2012-19 - 25.7
2012-20 - 25
2012-21 - 23.9
2012-22 - 19.8
2012-23 - 0

As you can see, the running total goes up and down.

This is the actual code I have for the "find total hours in the last 26 pay periods" query; the stuff about certifications, etc., is because in any given pay period, the employees may have hours recorded under multiple certifications.

SELECT List_Employees.ID, Sum(Items_Hours_Actually_Taken.HoursActual) AS SumOfHoursActual
FROM (List_Pay_Periods INNER JOIN (List_Employees INNER JOIN (Items_Certifications INNER JOIN Items_Hours_Actually_Taken ON Items_Certifications.[CertificationID] = Items_Hours_Actually_Taken.[HoursActualCertificationID]) ON List_Employees.ID = Items_Certifications.[CertificationEmployeeID]) ON List_Pay_Periods.[PayPeriodID] = Items_Hours_Actually_Taken.[HoursActualPayPeriod]) INNER JOIN Last_26_PP_From_Today ON List_Pay_Periods.PayPeriodID = Last_26_PP_From_Today.PayPeriodID
GROUP BY List_Employees.ID;

In case it's not clear, this query depends on a separate query, called Last_26_PP_From_Today:

SELECT List_Pay_Periods.PayPeriodID, List_Pay_Periods.PPEnd
FROM List_Pay_Periods
WHERE (((List_Pay_Periods.PPEnd)<Date() And (List_Pay_Periods.PPEnd)>(Date()-14)));

I also have a query that switches to find the last 26 pay periods from any particular date:

PARAMETERS [Date] DateTime;
SELECT List_Pay_Periods.PayPeriodID, List_Pay_Periods.PPEnd
FROM List_Pay_Periods
WHERE (((List_Pay_Periods.PPEnd)<[Date] And (List_Pay_Periods.PPEnd)>([Date]-14)));

The brute-force method I thought of in desperation involved a cascading series of Make Table queries, which was when I decided perhaps someone here could offer something cleaner.

Update

Thanks to Gord, I now have everything working except that I don't see the Pay Period numbers:

SELECT hbep1.Employee, hbep1.PP

(

SELECT Sum(hbep2.Hours) 
        FROM Hours_By_Employee_Per_PP AS hbep2
        WHERE hbep2.Employee=hbep1.Employee 
            AND (hbep2.PP Between hbep1.[PP]-25 And hbep1.[PP])

    ) AS SumLast26

FROM Hours_By_Employee_Per_PP AS hbep1;

That gets me:

Employee    SumLast26
2           12
2           12
2           12
2           18
2           91
3           4
3           8
3           88
3           168
3           180
5           15
5           15
5           15
7           43
7           61
7           75
7           97
7           106
7           121
9           19
9           0
Foi útil?

Solução

I hope this points you in the right direction:

I started with a table I called [Hours_by_Empl_PP] which has the total hours for each Employee in each individual Pay_Period.

EmployeeID  PayPeriodID HoursUsed
1           1           3
1           2           7
1           3           4
1           4           4
1           5           5
1           6           8
1           7           5
2           1           1
2           2           2
2           3           1
2           4           0
2           5           0
2           6           1
2           7           2

If your table data has multiple records for a given (Employee + Pay_Period) you can create a simple aggregation query to total up the values...

SELECT EmployeeID, PayPeriodID, SUM(HoursUsedToday) AS HoursUsed
FROM YourRawData
GROUP BY EmployeeID, PayPeriodID

...save that as [Hours_by_Empl_PP], and use that instead of a table.

The next step was to create a query to sum up the number of hours over a 4-period window. (I chose 4 instead of 26 just to make it easier to check my work.) This window includes the current Pay_Period and the previous three.

SELECT hbep1.EmployeeID, hbep1.PayPeriodID, 
    (
        SELECT Sum(hbep2.HoursUsed) 
        FROM Hours_by_Empl_PP hbep2
        WHERE hbep2.EmployeeID=hbep1.EmployeeID 
            AND (hbep2.PayPeriodID Between hbep1.[PayPeriodID]-3 And hbep1.[PayPeriodID])
    ) AS Sum_of_Hours_last_4_PPs
FROM Hours_by_Empl_PP hbep1;

This query gives me

EmployeeID  PayPeriodID Sum_of_Hours_last_4_PPs
1           1           3
1           2           10
1           3           14
1           4           18
1           5           20
1           6           21
1           7           22
2           1           1
2           2           3
2           3           4
2           4           4
2           5           3
2           6           2
2           7           3

Note that the query assumes that PayPeriodID values are sequential and in chronological order. You could achieve the same result using [PayPeriodEndDate] values, but that would mean another JOIN and I wanted to keep the example as clear as possible.

That's it, really. You can just save that query with a name like [Hours_by_Empl_4PP_window] and use it in your queries to JOIN on other tables (for Employee name, etc.) and take it from there.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top