问题
I'm using MS Access 2016 on a win10 platform. I have a table in Access tbl_OB_PLAN_ALLT_DISTRIB
that has the months of the year as headers example: OCT
, NOV
, DEC
, etc..
I have a query that calculates the total of the months dollar value for all my Organizations that money is sent to.
I am needing help modifying my code in my query to automatically add the next month field to that calculation. I currently have to go in the query and modify it every month.
Here is what I am using so far:
OB_Plan: Nz([Oct],0)+Nz([NOV],0)+Nz([DEC],0)+Nz([JAN],0)
This is placed as an expression in my query. So I would like a way to automatically add the next month in the expression. example:
OB_Plan: Nz([Oct],0)+Nz([NOV],0)+Nz([DEC],0)+Nz([JAN],0)+Nz([FEB],0)
I'm thinking I may need to make this a function and call the function in the expression.
Any ideas would be helpful. SQL Script modified:
SELECT tbl_OB_Plan_ALLT_DISTRIB_Data.Record_ID, ([tbl_OB_Plan_ALLT_DISTRIB_Data]![Directorate] & " " & "(" & [tbl_OB_Plan_ALLT_DISTRIB_Data]![FUND_CENTER] & ")") AS Directorate, tbl_OB_Plan_ALLT_DISTRIB_Data.SAG, tbl_OB_Plan_ALLT_DISTRIB_Data.MDEP, Calc_OB_Plan([JAN],[FEB],[MAR],[APR],[MAY],[JUN],[JUL],[AUG],[SEP],[OCT],[NOV],[DEC]) AS OB_Plan, [001-FINAL_INTEGRATION_TABLE]![AFP-FMEDDW] AS Current_AFP, [001-FINAL_INTEGRATION_TABLE]![ALLT-FMEDDW] AS Allotment_YTD, [001-FINAL_INTEGRATION_TABLE].TITLE
FROM tbl_OB_Plan_ALLT_DISTRIB_Data INNER JOIN [001-FINAL_INTEGRATION_TABLE] ON (tbl_OB_Plan_ALLT_DISTRIB_Data.MDEP = [001-FINAL_INTEGRATION_TABLE].MDEP) AND (tbl_OB_Plan_ALLT_DISTRIB_Data.SAG = [001-FINAL_INTEGRATION_TABLE].SAG)
GROUP BY tbl_OB_Plan_ALLT_DISTRIB_Data.Record_ID, ([tbl_OB_Plan_ALLT_DISTRIB_Data]![Directorate] & " " & "(" & [tbl_OB_Plan_ALLT_DISTRIB_Data]![FUND_CENTER] & ")"), tbl_OB_Plan_ALLT_DISTRIB_Data.SAG, tbl_OB_Plan_ALLT_DISTRIB_Data.MDEP, "", [001-FINAL_INTEGRATION_TABLE]![AFP-FMEDDW], [001-FINAL_INTEGRATION_TABLE]![ALLT-FMEDDW], [001-FINAL_INTEGRATION_TABLE].TITLE;
回答1:
The main reason that you are finding this difficult to achieve using standard MS Access functionality is because your database does not adhere to database normalisation rules.
The moment that you find yourself hard-coding month names into query expressions and consequently modifying the structure of your queries each month is a red flag that your database design should change.
In your case, based on the information you have provided, I would suggest defining either Month
(preferably as an integer) or, better yet, a Date
field in your table, with the data for each month appearing as separate records in the table, rather than on a single record.
Following this change, selection becomes simple, as you can easily calculate the months or date range that you wish to select within the selection criteria of your queries, without the need to modify the query definition going forward.
Without such redesign, the solutions will be ugly, for example:
select
choose
(
month(date()),
Nz([JAN],0),
Nz([JAN],0)+Nz([FEB],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0)+Nz([JUN],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0)+Nz([JUN],0)+Nz([JUL],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0)+Nz([JUN],0)+Nz([JUL],0)+Nz([AUG],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0)+Nz([JUN],0)+Nz([JUL],0)+Nz([AUG],0)+Nz([SEP],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0)+Nz([JUN],0)+Nz([JUL],0)+Nz([AUG],0)+Nz([SEP],0)+Nz([OCT],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0)+Nz([JUN],0)+Nz([JUL],0)+Nz([AUG],0)+Nz([SEP],0)+Nz([OCT],0)+Nz([NOV],0),
Nz([JAN],0)+Nz([FEB],0)+Nz([MAR],0)+Nz([APR],0)+Nz([MAY],0)+Nz([JUN],0)+Nz([JUL],0)+Nz([AUG],0)+Nz([SEP],0)+Nz([OCT],0)+Nz([NOV],0)+Nz([DEC],0)
)
from
tbl_OB_PLAN_ALLT_DISTRIB
Or:
select sum(t.amount)
from
(
select 1 as mon, Nz([JAN],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 2 as mon, Nz([FEB],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 3 as mon, Nz([MAR],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 4 as mon, Nz([APR],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 5 as mon, Nz([MAY],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 6 as mon, Nz([JUN],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 7 as mon, Nz([JUL],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 8 as mon, Nz([AUG],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 9 as mon, Nz([SEP],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 10 as mon, Nz([OCT],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 11 as mon, Nz([NOV],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
union
select 12 as mon, Nz([DEC],0) as amount
from tbl_OB_PLAN_ALLT_DISTRIB
) t
where
t.mon <= month(date())
Or, as a VBA function:
Function Calc_OB_Plan(vJan, vFeb, vMar, vApr, vMay, vJun, vJul, vAug, vSep, vOct, vNov, vDec) As Double
Dim Arr()
Arr = Array(vJan, vFeb, vMar, vApr, vMay, vJun, vJul, vAug, vSep, vOct, vNov, vDec)
Dim i As Integer
For i = 0 To Month(Date) - 1
Calc_OB_Plan = Calc_OB_Plan + Nz(Arr(i), 0)
Next i
End Function
Which could be called from your SQL query in the following way:
select Calc_OB_Plan([JAN],[FEB],[MAR],[APR],[MAY],[JUN],[JUL],[AUG],[SEP],[OCT],[NOV],[DEC]) as OB_Plan
from tbl_OB_PLAN_ALLT_DISTRIB
EDIT:
Since you are grouping by all fields, without any aggregation functions, you can replace the group by
clause with a select distinct
to obtain the same result more efficiently, e.g.:
SELECT DISTINCT
tbl_OB_Plan_ALLT_DISTRIB_Data.Record_ID,
([tbl_OB_Plan_ALLT_DISTRIB_Data]![Directorate] & " " & "(" & [tbl_OB_Plan_ALLT_DISTRIB_Data]![FUND_CENTER] & ")") AS Directorate,
tbl_OB_Plan_ALLT_DISTRIB_Data.SAG,
tbl_OB_Plan_ALLT_DISTRIB_Data.MDEP,
Calc_OB_Plan([JAN],[FEB],[MAR],[APR],[MAY],[JUN],[JUL],[AUG],[SEP],[OCT],[NOV],[DEC]) AS OB_Plan,
[001-FINAL_INTEGRATION_TABLE]![AFP-FMEDDW] AS Current_AFP,
[001-FINAL_INTEGRATION_TABLE]![ALLT-FMEDDW] AS Allotment_YTD,
[001-FINAL_INTEGRATION_TABLE].TITLE
FROM
tbl_OB_Plan_ALLT_DISTRIB_Data INNER JOIN [001-FINAL_INTEGRATION_TABLE] ON
tbl_OB_Plan_ALLT_DISTRIB_Data.MDEP = [001-FINAL_INTEGRATION_TABLE].MDEP AND
tbl_OB_Plan_ALLT_DISTRIB_Data.SAG = [001-FINAL_INTEGRATION_TABLE].SAG
来源:https://stackoverflow.com/questions/59898124/how-to-automaticaly-calculate-a-new-field-column-in-ms-access-db-2016-each-mon