I have the following table:
contract_ID
Contract_start_date
Contract_Duration
Contract_amount
Fixed_premium
Pay_every_month
Sample Data:
contract_ID: 5
Contract_start_date: 01/01/2014
Contract_Duration: 3 years
Contract_amount: $90.000
Fixed_premium: $15000
Pay_every_month: 6 months
There should be an access query that uses the contracts data to generate a payments schedule as follows:
Contract ID......Due Date...............Amount Due
5 01 / 01 / 2014 $15.000
5 01 / 07 / 2014 $15.000
5 01 / 01 / 2015 $15.000
5 01 / 07 / 2015 $15.000
5 01 / 01 / 2016 $15.000
5 01 / 07 / 2016 $15.000
I used this SQL statement and it's not working:
SELECT
Contracts.contract_ID,
DateAdd("m",[Pay_every_month],[Contracts]![Contract_start_date]) AS Due_Date,
Contracts.Fixed_premium AS Amount_due
FROM Contracts;
Access database file is HERE
You can accomplish your goal with Access SQL using a "numbers table". Create a table named [NumbersFromZero] containing integer values starting from zero and going as high as necessary to cover the largest number of payments for any contract, e.g.,
n
--
0
1
2
3
...
98
99
Once that is in place, if we have test data like this in [Contracts]
contract_ID Contract_start_date Contract_Duration Contract_amount Fixed_premium Pay_every_month
----------- ------------------- ----------------- --------------- ------------- ---------------
5 2014-01-01 3 90000 15000 6
then the following query
SELECT
Contracts.contract_ID,
DateAdd("m", NumbersFromZero.n * Contracts.Pay_every_month, Contracts.Contract_start_date) AS Due_date,
Contracts.Fixed_premium AS Amount_due
FROM Contracts, NumbersFromZero
WHERE NumbersFromZero.n < (Contracts.Contract_Duration * 12 / Contracts.Pay_every_month)
will return
contract_ID Due_date Amount_due
----------- ---------- ----------
5 2014-01-01 15000
5 2014-07-01 15000
5 2015-01-01 15000
5 2015-07-01 15000
5 2016-01-01 15000
5 2016-07-01 15000
Related
I need to find the average days past due for the last 3 months for each client. Not as a rolling/moving average, but one time number, always calculating the last 3 months, no matter if the data changes.
For example now the last data I have is from Sept 2022, so I need the average of Sept 2022, August 2022 and July 2022. But if the data changes and now I have October 2022, then I would need average of Oct, Sept, August and so on.
I tried this but it calculates wrong
CREATE TABLE AVERAGE_dpd
AS (
SELECT "SUM_WEIGHTED_AVG_PERMONTH"."NAME",
AVG("SUM_WEIGHTED_AVG_PERMONTH"."SUM")
OVER (PARTITION BY "SUM_WEIGHTED_AVG_PERMONTH"."NAME"
order by MONTH ("SUM_WEIGHTED_AVG_PERMONTH"."LAST DAY OF MONTH_NETDUEDATE") desc
rows between 2 preceding and CURRENT ROW)
as AVG3Months
FROM "SUM_WEIGHTED_AVG_PERMONTH");
Thank you so much for your help!
I assume you are expecting this result:
client_name | avg_last_3mth
-------------+--------------
Client 01 | 16.76
Client 02 | 5.75
Client 03 | -13.95
So I assume you have something like this as input data (and this is how we usually like the data to accompany the question):
month_begin | client_name | dpd
------------+-------------+----
2022-01-05 | Client 01 | 12
2022-01-06 | Client 01 | 14
2022-01-07 | Client 01 | 18
2022-01-08 | Client 01 | 17
2022-01-05 | Client 02 | 12
2022-01-06 | Client 02 | 14
2022-01-07 | Client 02 | 18
2022-01-08 | Client 02 | 17
2022-01-05 | Client 03 | 12
2022-01-06 | Client 03 | 14
2022-01-07 | Client 03 | 18
2022-01-08 | Client 03 | 17
With this input data, you probably want the rows with month_begin of the first of the current month (TRUNC(CURRENT_DATE,'MONTH')), plus the two previous months. And this is what I do, then I obviously group by the client name:
WITH
-- input data I made up, don't use in query ..
dpd(month_begin,client_name,dpd) AS (
SELECT DATE '2022-05-01','Client 01',12
UNION ALL SELECT DATE '2022-06-01','Client 01',14
UNION ALL SELECT DATE '2022-07-01','Client 01',18
UNION ALL SELECT DATE '2022-08-01','Client 01',17
UNION ALL SELECT DATE '2022-05-01','Client 02', 2
UNION ALL SELECT DATE '2022-06-01','Client 02', 4
UNION ALL SELECT DATE '2022-07-01','Client 02', 8
UNION ALL SELECT DATE '2022-08-01','Client 02', 7
UNION ALL SELECT DATE '2022-05-01','Client 03',22
UNION ALL SELECT DATE '2022-06-01','Client 03',24
UNION ALL SELECT DATE '2022-07-01','Client 03',28
UNION ALL SELECT DATE '2022-08-01','Client 03',27
)
-- real query starts here ..
SELECT
client_name
, AVG(dpd)::NUMERIC(5,2) AS avg_last_3mth
FROM dpd
WHERE month_begin >= TRUNC(CURRENT_DATE,'MONTH') - '2 MONTHS'::INTERVAL YEAR TO MONTH
GROUP BY
client_name;
-- out client_name | avg_last_3mth
-- out -------------+---------------
-- out Client 02 | 6.33
-- out Client 01 | 16.33
-- out Client 03 | 26.33
I have two tables:
Meter
ID SerialNumber
=======================
1 ABC1
2 ABC2
3 ABC3
4 ABC4
5 ABC5
6 ABC6
RegisterLevelInformation
ID MeterID ReadValue Consumption PreviousReadDate ReadType
============================================================================
1 1 250 250 1 jan 2015 EST
2 1 550 300 1 feb 2015 ACT
3 1 1000 450 1 apr 2015 EST
4 2 350 350 1 jan 2015 EST
5 2 850 500 1 feb 2015 ACT
6 2 1000 150 1 apr 2015 ACT
7 3 1500 1500 1 jan 2015 EST
8 3 2500 1000 1 mar 2015 EST
9 3 5000 2500 4 apr 2015 EST
10 4 250 250 1 jan 2015 EST
11 4 550 300 1 feb 2015 ACT
12 4 1000 450 1 apr 2015 EST
13 5 350 350 1 jan 2015 ACT
14 5 850 500 1 feb 2015 ACT
15 5 1000 150 1 apr 2015 ACT
16 6 1500 1500 1 jan 2015 EST
17 6 2500 1000 1 mar 2015 EST
18 6 5000 2500 4 apr 2015 EST
I am trying to group by meter serial and return the last actual read date for each of the meters but I am unsure as to how to accomplish this. Here is the sql I have thus far:
select a.SerialNumber, ReadTypeCode, MAX(PreviousReadDate) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
where ReadType = 'ACT'
group by a.SerialNumber,b.ReadTypeCode, PreviousReadDate
order by a.SerialNumber
I can't seem to get the MAX function to take effect in returning only the latest actual reading row and it returns all dates and the same meter serial is displayed several times.
If I use the following sql:
select a.SerialNumber, count(*) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
group by a.SerialNumber
order by a.SerialNumber
then each serial is shown only once. Any help would be greatly appreciated.
Like #PaulGriffin said in his comment you need to remove PreviousReadDate column from your GROUP BY clause.
Why are you experiencing this behaviour?
Basically the partition you have chosen - (SerialNumber,ReadTypeCode,PreviousReadDate) for each distinct pair of those values prints you SerialNumber, ReadTypeCode, MAX(PreviousReadDate). Since you are applying a MAX() function to each row of the partition that includes this column you are simply using an aggregate function on one value - so the output of MAX() will be equal to the one without it.
What you wanted to achieve
Get MAX value of PreviousReadDate for every pair of (SerialNumber,ReadTypeCode). So this is what your GROUP BY clause should include.
select a.SerialNumber, ReadTypeCode, MAX(PreviousReadDate) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
where ReadType = 'ACT'
group by a.SerialNumber,b.ReadTypeCode
order by a.SerialNumber
Is the correct SQL query for what you want.
Difference example
ID MeterID ReadValue Consumption PreviousReadDate ReadType
============================================================================
1 1 250 250 1 jan 2015 EST
2 1 550 300 1 feb 2015 ACT
3 1 1000 450 1 apr 2015 EST
Here if you apply the query with grouping by 3 columns you would get result:
SerialNumber | ReadTypeCode | PreviousReadDate
ABC1 | EST | 1 jan 2015 -- which is MAX of 1 value (1 jan 2015)
ABC1 | ACT | 1 feb 2015
ABC1 | EST | 1 apr 2015
But instead when you only group by SerialNumber,ReadTypeCode it would yield result (considering the sample data that I posted):
SerialNumber | ReadTypeCode | PreviousReadDate
ABC1 | EST | 1 apr 2015 -- which is MAX of 2 values (1 jan 2015, 1 apr 2015)
ABC1 | ACT | 1 feb 2015 -- which is MAX of 1 value (because ReadTypeCode is different from the row above
Explanation of your second query
In this query - you are right indeed - each serial is shown only once.
select a.SerialNumber, count(*) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
group by a.SerialNumber
order by a.SerialNumber
But this query would produce you odd results you don't expect if you add grouping by more columns (which you have done in your first query - try it yourself).
You need to remove PreviousReadDate from your Group By clause.
This is what your query should look like:
select a.SerialNumber, ReadTypeCode, MAX(PreviousReadDate) from Meter as a
left join RegisterLevelInformation as b on a.MeterID = b.MeterID
where ReadType = 'ACT'
group by a.SerialNumber,b.ReadTypeCode
order by a.SerialNumber
To understand how the group by clause works when you mention multiple columns, follow this link: Using group by on multiple columns
You will understand what was wrong with your query and why it returns all dates and the same meter serial is displayed several times.
Good luck!
Kudos! :)
Similar to the following:
Count days within a month from date range
I want to find a way, within the MS-Access Query Design environment, to create fields that count the number of month/year days within a date range.
Here is what I want the data to look like:
Row | StartDate | EndDate | #DaysJan2010 | #DaysFeb2010 | #DaysMarch2010
001 01/02/2010 02/04/2012 29 28 31
002 01/02/2010 01/05/2010 4 0 0
003 04/02/2010 05/05/2010 0 0 0
004 01/02/2010 02/04/2012 29 28 31
005 02/02/2012 02/03/2012 0 2 0
Please keep in mind that both month and year are important because I need to be able to distinguish between the number of days that fall within a given date range for January 2010 and January 2011, as opposed to just the number of days within a given date range that are in January.
If there is a systematic way of performing of creating these fields by using SQL in Access, that would be my preferred method.
However, in the event that it is impossible (or very difficult) to do so, I would like to know how to build each field in the expression builder, so that I may at least be able to generate the count fields one at a time.
As always, thank you very much for your time.
There are cases where date manipulations can be aided by a "dates table". Similar to a "numbers table", a "dates table" is a table containing one row for every date in a given range, usually covering the entire range of dates that one could expect to encounter in the actual data.
For sample data in a table named [SampleData]
Row StartDate EndDate
--- ---------- ----------
001 2010-01-02 2012-02-04
002 2010-01-02 2010-01-05
003 2010-04-02 2010-05-05
004 2010-01-02 2012-02-04
005 2012-02-02 2012-02-03
and a [DatesTable] that is simply
theDate
----------
2010-01-01
2010-01-02
2010-01-03
...
2012-12-30
2012-12-31
the query
SELECT
sd.Row,
dt.theDate,
Year(dt.theDate) AS theYear,
Month(dt.theDate) AS theMonth
FROM
SampleData AS sd
INNER JOIN
DatesTable AS dt
ON dt.theDate >= sd.StartDate
AND dt.theDate <= sd.EndDate
returns a row for each date in the interval for each [SampleData].[Row] value. (For this particular sample data, that's 1568 rows in total.)
Performing an aggregation on that
SELECT
Row,
theYear,
theMonth,
COUNT(*) AS NumberOfDays
FROM
(
SELECT
sd.Row,
dt.theDate,
Year(dt.theDate) AS theYear,
Month(dt.theDate) AS theMonth
FROM
SampleData AS sd
INNER JOIN
DatesTable AS dt
ON dt.theDate >= sd.StartDate
AND dt.theDate <= sd.EndDate
) AS allDates
GROUP BY
Row,
theYear,
theMonth
gives us all of the counts
Row theYear theMonth NumberOfDays
--- ------- -------- ------------
001 2010 1 30
001 2010 2 28
001 2010 3 31
001 2010 4 30
001 2010 5 31
001 2010 6 30
001 2010 7 31
001 2010 8 31
001 2010 9 30
001 2010 10 31
001 2010 11 30
001 2010 12 31
001 2011 1 31
001 2011 2 28
001 2011 3 31
001 2011 4 30
001 2011 5 31
001 2011 6 30
001 2011 7 31
001 2011 8 31
001 2011 9 30
001 2011 10 31
001 2011 11 30
001 2011 12 31
001 2012 1 31
001 2012 2 4
002 2010 1 4
003 2010 4 29
003 2010 5 5
004 2010 1 30
004 2010 2 28
004 2010 3 31
004 2010 4 30
004 2010 5 31
004 2010 6 30
004 2010 7 31
004 2010 8 31
004 2010 9 30
004 2010 10 31
004 2010 11 30
004 2010 12 31
004 2011 1 31
004 2011 2 28
004 2011 3 31
004 2011 4 30
004 2011 5 31
004 2011 6 30
004 2011 7 31
004 2011 8 31
004 2011 9 30
004 2011 10 31
004 2011 11 30
004 2011 12 31
004 2012 1 31
004 2012 2 4
005 2012 2 2
We can then report on that, or crosstab it, or do any number of other fun things.
Side note:
One circumstance where a "dates table" can be very useful is when we have to deal with Statutory Holidays. That is because
Sometimes the "day off" for a Statutory Holiday is not the actual day. If "International Bacon Day" falls on a Sunday then we might get the Monday off.
Some Statutory Holidays can be tricky to calculate. For example, Good Friday for us Canadians is (if I remember correctly) "the Friday before the first Sunday after the first full moon after the Spring Equinox".
If we have a "dates table" then we can add a [StatutoryHoliday] Yes/No field to flag all of the (observed) holidays and then use ... WHERE NOT StatutoryHoliday to exclude them.
HI, I have the following table which save agent ranking on daily basis on basis of tickets status.
No. **Agent Name** **Incidents** **workorder** **Rank** **TimeStamp**
1 cedric 200 29 1 21 Jan 2011
2 poul 100 10 2 21 Jan 2011
3 dan 200 20 1 21 Jan 2011
4 cedric 100 19 2 22 Jan 2011
5 poul 200 26 1 22 Jan 2011
6 dan 150 20 2 22 Jan 2011
Now i need query which fetch ranking between two dates means if i select date between 21 jan 2011 to 22 jan 2011 then query return me agents average ranking between these two dates of agent not return the agent ranking details on date wise. I need single name of agent with his ranking.
Regards,
Iftikhar hashmi
Try
SELECT [Agent Name], AVG(RANK) FROM MY_TABLE WHERE [TimeStamp] BETWEEN DATE1 AND DATE2
GROUP BY [Agent Name]
(Update)
Thanks to Martin which reminded me I need to cast RANK.
SELECT [Agent Name], AVG(CAST(RANK AS FLOAT)) FROM MY_TABLE WHERE [TimeStamp] BETWEEN DATE1 AND DATE2
GROUP BY [Agent Name]
I have a table some thing like as follows for Inventory details.
InventoryTable.
InventoryTableID DateCreated quantity ItemName
-------------------------------------------------
1 2010-02-04 12 abc
2 2010-03-10 4 abc
3 2010-03-13 5 xyz
4 2010-03-13 19 def
5 2010-03-17 15 abc
6 2010-03-29 15 abc
7 2010-04-01 22 xyz
8 2010-04-13 5 abc
9 2010-04-15 6 def
from the above table if my admin wants to know the inventory details for month April 2010 (i.e. Apr 1st 2010 - Apr 30th 2010)
I need the output as shown below.
inventory as on Apr 1st 2010
ItemName Datecreated qty
----------------------------
abc 2010-03-29 15
xyz 2010-04-01 22
def 2010-03-13 19
inventory as on Apr 30th 2010
ItemName Datecreated qty
---------------------------
abc 2010-04-13 5
xyz 2010-04-01 22
def 2010-04-15 6
For your first result set, run with #YourDataParam = '2010-04-01'. For the second set, use '2010-04-30'.
;with cteMaxDate as (
select it.ItemName, max(it.DateCreated) as MaxDate
from InventoryTable it
where it.DateCreated <= #YourDataParam
group by it.ItemName
)
select it.ItemName, it.DateCreated, it.qty
from cteMaxDate c
inner join InventoryTable it
on c.ItemName = it.ItemName
and c.MaxDate = it.DateCreated