SSAS Tabular - how to aggregate differently at month grain? - dax

In my cube, I have several measures at the day grain that I'd like to sum at the day grain but average (or take latest) at the month grain or year grain.
Example:
We have a Fact table with Date and number of active subscribers in that day (aka PMC). This is snapshotted per day.
dt
SubscriberCnt
1/1/22
50
1/2/22
55
This works great at the day level. At the month level, we don't want to sum these two values (count = 105) because it doesn't make sense and not accurate.
when someone is looking at month grain, it should look like this - take the latest for the month. (we may change this to do an average instead, management is still deciding)
option 1 - Take latest
Month-Dt
Subscribers
Jan-2022
55
Feb-2022
-
option 2 - Take aveage
Month-Dt
Subscribers
Jan-2022
52
Feb-2022
-
I've not been able to find the right search terms for this but this seems like a common problem.

I added some sample data at the end of a month for testing:
dt
SubscriberCnt
12/30/21
46
12/31/21
48
This formula uses LASTNONBLANKVALUE, which sorts by the first column and provides the latest value that is not blank:
Monthly Subscriber Count = LASTNONBLANKVALUE( 'Table'[dt], SUM('Table'[SubscriberCnt]) )
If you do an AVERAGE, a simple AVERAGE formula will work. If you want an average just for the current month, then try this:
Current Subscriber Count =
VAR _EOM = CLOSINGBALANCEMONTH( SUM('Table'[SubscriberCnt]), DateDim[Date] )
RETURN IF(_EOM <> 0, _EOM, AVERAGE('Table'[SubscriberCnt]) )
But the total row will be misleading, so I would add this so the total row is the latest number:
Current Subscriber Count =
VAR _EOM = CLOSINGBALANCEMONTH( SUM('Table'[SubscriberCnt]), DateDim[Date] ) //Get the number on the last day of the month
VAR _TOT = NOT HASONEVALUE(DateDim[MonthNo]) // Check if this is a total row (more than one month value)
RETURN IF(_TOT, [Monthly Subscriber Count], // For total rows, use the latest nonblank value
IF(_EOM <> 0, _EOM, AVERAGE('Table'[SubscriberCnt]) ) // For month rows, use final day if available, else use the average
)

Related

Calculate Total Amount for a specific period

I want to calculate total value between two dates in DAX. I have a formula SUM(C5:C16) in excel sheet, which C5 is the sales amount for a specific date (last year + 1month), and C16 is the sales amount for current row date.
I tried this formula in DAX, but it did not return sum value:
var Rolling = CALCULATE(sum('proces'[HOURS]),DATESINPERIOD('Date'[DateField],ENDOFMONTH('proces'[date_start]),-12,MONTH))
Also, I tried this one, but it is not working:
=SumX (
var prev=DATEADD(DATEADD('proces'[date_start] ,-1,YEAR),+1,MONTH)
return
Filter ( 'proces',
'proces'[date_end] <= Earlier ( 'proces'[date_end] ) &&
'proces'[date_start]>=prev,
'proces'[HOURS])
Also, I tried this one but it returns nothing
=CALCULATE(
SUMX('proces','proces'[HOURS]),
DATESBETWEEN(
'Date'[DateField],
STARTOFMONTH(DATEADD(LASTDATE('Date'[DateField]),-1,MONTH)),
ENDOFMONTH(DATEADD('Date'[DateField],-1,MONTH))
)
)
You seem to be confused about variables in DAX and your formulas are not even valid DAX expressions. Learn about variables in the official documentation:
Use variables to improve your DAX formulas
If you need further help with calculating the your total amount, add sample data to your question.

prometheus filter range vector by day_of_week

I use sub-queries to get hourly aggregated values for the last week for example: The number of http requests per hour over the whole last week, which will return 168 values in a range vector.
delta(http_server_requests_seconds_count[1h])[1w:1h]
Now I want to filter the value to return only the ones which are for a specific week day, lets say return only the 24 value from Monday.
I found some hints about day_of_week, timestamp, bool expr, but I cannot combine them to get it working or maybe it is not possible? Something like:
delta(http_server_requests_seconds_count[1h])[1w:1h] bool day_of_week() == 1
It'd be more effficient to adjust your start/end time to only over the day, but you could do:
(increase(http_server_requests_seconds_count[1h]) and on () day_of_week() == 1)[1w:1h]

Power Query (M language) 50 day moving Average

I have a list of products and would like to get a 50 day simple moving average of its volume using Power Query (M).
The table is sorted by product name and date. I add a custom column and applied the code below.
if [date] >= #date(2018,1,29)
then List.Average(List.Range(Source[Volume],[Volume]-1,-50))
else ""
Since it is already sorted by date and name, an if statement was applied with a date as criteria/filter. However, an error occurs that says
'Volume' column not found in the table.
I expect to have an added column in the power query with volume 50 day moving average per product. the calculation to be done if date is greater than or equal Jan 29, 2018.
We don't know what your columns are, but assuming you have [product], [date] and [volume] in Source, this would average the last 50 days of [volume] for the identical [product] based on each [date], and place in a new column
AvgAmountAdded = Table.AddColumn(Source, "AverageAmount", (i) => List.Average(Table.SelectRows(Source, each ([product] = i[product] and [date]<=i[date] and [date]>=Date.AddDays(i[date],-50)))[volume]), type number)
Finally! found a solution.
First, apply Index by product see this post for further details
Then index again without criteria (index all rows)
Then, apply below code
= Table.AddColumn(#"Previous Step", "Volume SMA(50)", each if [Index_byProduct] >= 50 then List.Average(List.Range(#"Previous Step"[Volume], ([Index_All]-50),50)) else 0),
For large dataset, Table.Buffer function is recommended after index-expand step to improve PQ calculation speed

Time aligned variable in stata

I have a panel data set for multiple waves (13) for roughly 10,000 individuals each year, with people entering and exiting at various time points. I am interested in what happens as people become diagnosed with a disease over time. Therefore I need to recode the time variable so that it becomes t=0 the first wave when diagnosed, then t=1 is the next year and so on, so that all of my individuals are comparable (and I guess -1 for t-1 etc). However I am unsure about how to go about this in stata. Would anyone be able to advise? Many thanks
The case of one diagnosis per person
clear all
set more off
*----- example data -----
set obs 100
set seed 2357
generate id = _n
generate year = floor(10 * runiform()) + 1990
expand 5
bysort id: replace year = year + _n
bysort id (year): generate diag = cond(_n == 3, 1, 0)
list in 1/20, sepby(id)
*----- what you seek -----
bysort id (diag): gen time = year - year[_N]
sort id year
list in 1/20
I assume the same data structure as #RichardHerron and use his example. diag is an indicator variable that takes on the value of 1 at the time of diagnosis and 0 otherwise (only one diagnosis per person is considered).
The sorting done by bysort is critical. The observation holding the time of diagnosis is pushed to the end of the database (by id groups) and then all that's left to do is compare (subtract) all years with that reference year. See help _variables for details on system variables like _N.
The case of multiple diagnoses per person
If several diagnoses are made per person, but we care only for the first occurence (according to year), we could do:
gsort id diag -year
by id: gen time = year - year[_N]
Simple but not optimal solution
Suppose diagnosis is 1 when diagnosed (at most once per person) and 0 otherwise.
Then the time at diagnosis is at its simplest
egen time_diagnosis = total(diagnosis * year), by(id)
but you need to ignore any zeros. To spell that out,
replace time_diagnosis = . if time_diagnosis == 0
Better alternative
A more complicated but preferable alternative can handle multiple diagnoses if they occur:
egen time_diagnosis = min(year / diagnosis), by(id)
as year / diagnosis is year when diagnosis is 1 and missing otherwise. This yields missing values if there is no diagnosis, which is as it should be.
Then you subtract that to get a new time variable.
gen time2 = time - time_diagnosis
In short, I think you can get this done in two statements, handling panel structure too.
Update
#Richard Herron asks why use egen with by(), and not just
gen time_diagnosis = time * diagnosis
A limitation of that is that the "correct" value is contained only in those observations for which diagnosis is 1; that value still has to be "spread" to other values for the same id. But that is precisely what egen does here. In the simplest situation, with one diagnosis the total of time * diagnosis is just time * 1 or time, as any zeros make no difference to the sum.
It is usually helpful to provide test data, but here they are easy enough to generate. The trick is to find the first year for each individual (my fyear), which I'll do with min() from egen. Then I'll subtract this first year fyear from the actual year to find the year relative to diagnosis ryear.
/* generate panel */
clear
set obs 10000
generate id = _n
generate year = floor(10 * runiform()) + 1990
expand 10
bysort id: replace year = year + _n
sort id year
list in 1/20
/* generate relative year */
bysort id: egen fyear = min(year)
generate ryear = year - fyear
list in 1/20
If the first year in the panel is not diagnosis, then just construct fyear based on diagnosis criteria.
Edit: Thinking more on this, maybe it's the last part that you're having a hard time with (i.e., identifying the diagnosis year to subtract from the calendar year). Here's what I would do.
bysort id (year): generate diagnosis = cond(_n == 5, 1, 0)
preserve
tempfile diagnosis
keep if (diagnosis == 1)
rename year dyear
keep id dyear
save `diagnosis'
restore
merge m:1 id using `diagnosis', nogenerate
generate ryear2 = year - dyear

Visual Studio 2008 Report Designer (complex general ledger)

I'm combining reports to create a single general ledger report, currently it consists of 84 seperate reports. My idea is the end user will have a drop down for the department and month. These are my columns:
Account Number Account Description Current Period Actual
YTD Actual YTD Budget YTD Budget Variance
Total YR Budget Account Status
I have most of it figured out, but can't understand how to figure YTD Actual and YTD Budget since these will require a Sum of multiple Fields depending on what month and department is selected.
My where statement goes something like this and takes care of the current period actual and account number:
Where
( gl_master.acct_cde = gl_master_comp_v.acct_cde ) and
( gl_master.budget_officer = budget_off_mstr.budget_officer ) and
( ( gl_master_comp_v.acct_comp1 = '01' ) AND
( budget_off_mstr.budget_officer IN (#BudgetOfficer) ) ) AND
((#Month = 1 AND gl_master.post_bal_mon_1) OR
(#Month = 2 AND gl_master.post_bal_mon_2)...
How can I have the query recognize what needs to be put into the column when there are multiple fields being summed.
Thanks for any insight. If you made something like this before a small sample of it would be very helpful.
I worked it out.
It needs to be done in a calculated field within the dataset. Then a sum can be done on the field in the textbox.
small chunk of calculated field:
=Cdec(Switch(Parameters!Month.Value = 1, Fields!post_bal_mon_1.Value,
Parameters!Month.Value = 2, Fields!post_bal_mon_2.Value + Fields!post_bal_mon_1.Value,
Parameters!Month.Value = 3, Fields!post_bal_mon_3.Value + Fields!post_bal_mon_1.Value + Fields!
post_bal_mon_2.Value,
Parameters!Month.Value = 4, Fields!post_bal_mon_4.Value + Fields!post_bal_mon_1.Value + Fields!
post_bal_mon_2.Value + Fields!post_bal_mon_3.Value,...))
textbox for sum(I place this in footer):
=SUM(Fields!post_bal_mon_1.value, "DataSet1")

Resources