AVERAGEX Confusion - dax

In my data model I have a table named 'Online Sales' and a Dates table (daily dates from 2005 to 2010). They are joined M:1.
I am attempting to use AVERAGEX in the following ways. The first approach grossly inflates my daily average when placed in a matrix containing a filter context of year and month. The second approach generates correct results. I don't understand why they both don't produce the same results.
1
Average Sales By Day =
AVERAGEX(
'Dates',
[Sales Amount Online]
)
2
Average Sales By Day =
AVERAGEX(
'Online Sales'
[Sales Amount Online]
)
[Sales Amount Online] is a measure as follows:
Sales Amount Online = SUMX(
'Online Sales',
'Online Sales'[Sales Quantity] * 'Online Sales'[Unit Price] - 'Online Sales'[Discount Amount]
)

In the first measure, you are iterating through each row in the 'Dates' table and calculating [Sales Amount Online] for each day (assuming daily level granularity).
When you evaluate the [Sales Amount Online] measure with a day as your filter context, you get the sum of all sales that occur on that day (which could be many).
In the second measure, you are iterating through each row in the 'Online Sales' table and calculating [Sales Amount Online] for each transaction (assuming that's what each row represents).
When you evaluate [Sales Amount Online] measure within 'Online Sales' row context, the measure only sums sales from that single row (assuming all rows are unique).
Basically, #1 is average per day and #2 is average per transaction (provided my assumptions are correct).

Related

DAX formula to get total number of sales in a Calculated Column at a lookup table

I have received answers to my last question. Thanks to all. Now I have another query. I have a lookup table, called Products and a transaction table, called Sales. The relationship between them is one to many. I want to make a Calculated Column at Product to get the total number of sales for each product. I tried to apply Calculate function as solution.
Product [total number of sales] =
Countrows ( Filter (Product, Calculate (Sum( Sales [SalesAmount])))).
I expected products in each row in Product table shall filter the sum of sales amount and generate a virtual table with all the entries related to a particular product. And finally, Countrows shall count the number of entries. But on the contrary, it resulted with same number in each row.
I am just a beginner in DAX. I tried to solve it depending on context transition concept. But my guess was wrong. Please help me out. Thank you in advance.
Use RELATEDTABLE:
If you just want the number of entries in the Sales table per product:
=
COUNTROWS(
RELATEDTABLE( Sales )
)
If you want the total sales per product:
=
SUMX(
RELATEDTABLE( Sales ),
Sales[SalesAmount]
)

AggregatingMergeTree not aggregating inserts properly

I have a table that aggregates the number of sales across various products by minute/hour/day and computes various metrics.
The table below has 1 minute increment calculations that compute off core_product_tbl. After the computations are in product_agg_tbl, other tables compute by hour, day, week etc off of product_agg_tbl.
CREATE TABLE product_agg_tbl (
product String,
minute DateTime,
high Nullable(Float32),
low Nullable(Float32),
average AggregateFunction(avg, Nullable(Float32)),
first Nullable(Float32),
last Nullable(Float32),
total_sales Nullable(UInt64)
)
ENGINE = AggregatingMergeTree
PARTITION BY toYYYYMM(minute)
ORDER BY (product, minute);
CREATE MATERIALIZED VIEW product_agg_mv TO product_agg_tbl AS
SELECT
product,
minute,
max(price) AS high,
min(price) AS low,
avgState(price) AS average,
argMin(price, sales_timestamp) AS first,
argMax(price, sales_timestamp) AS last,
sum(batch_size) as total_sales
FROM core_product_tbl
WHERE minute >= today()
GROUP BY product, toStartOfMinute(sales_timestamp) AS minute;
CREATE VIEW product_agg_1w AS
SELECT
product,
toStartOfHour(minute) AS minute,
max(high) AS high,
min(low) AS low,
avgMerge(average) AS average_price,
argMin(first, minute) AS first,
argMax(last, minute) AS last,
sum(total_sales) as total_sales
FROM product_agg_tbl
WHERE minute >= date_sub(today(), interval 7 + 7 day)
GROUP BY product, minute;
The issue I have is that when I run the query below straight off of core_product_tbl, I get much different numbers than product_agg_1w. What could be going on?
SELECT
product,
toStartOfHour(minute) AS minute,
max(price) AS high,
min(price) AS low,
avgState(price) AS average,
argMin(price, sales_timestamp) AS first,
argMax(price, sales_timestamp) AS last,
sum(batch_size) as total_sales
FROM core_product_tbl
WHERE minute >= today()
GROUP BY product, toStartOfMinute(sales_timestamp) AS minute;
You should use SimpleAggregateFunction or AggregateFunction in the table AggregatingMergeTree.
AggregatingMergeTree knows nothing about Materialized View and about select in the Materialized View. https://den-crane.github.io/Everything_you_should_know_about_materialized_views_commented.pdf
CREATE TABLE product_agg_tbl (
product String,
minute DateTime,
high SimpleAggregateFunction(max, Nullable(Float32)),
low SimpleAggregateFunction(min, Nullable(Float32)),
average AggregateFunction(avg, Nullable(Float32), DateTime),
first AggregateFunction(argMin, Nullable(Float32), DateTime),
last AggregateFunction(argMax, Nullable(Float32),DateTime),
total_sales SimpleAggregateFunction(sum,Nullable(UInt64))
)
ENGINE = AggregatingMergeTree
PARTITION BY toYYYYMM(minute)
ORDER BY (product, minute);
CREATE MATERIALIZED VIEW product_agg_mv TO product_agg_tbl AS
SELECT
product,
minute,
max(price) AS high,
min(price) AS low,
avgState(price) AS average,
argMinState(price, sales_timestamp) AS first,
argMaxState(price, sales_timestamp) AS last,
sum(batch_size) as total_sales
FROM core_product_tbl
WHERE minute >= today()
GROUP BY product, toStartOfMinute(sales_timestamp) AS minute;
CREATE VIEW product_agg_1w AS
SELECT
product,
toStartOfHour(minute) AS minute,
max(high) AS high,
min(low) AS low,
avgMerge(average) AS average_price,
argMinMerge(first, minute) AS first,
argMaxMerge(last, minute) AS last,
sum(total_sales) as total_sales
FROM product_agg_tbl
WHERE minute >= date_sub(today(), interval 7 + 7 day)
GROUP BY product, minute;
Don't use view (product_agg_1w) because it's counterproductive for performance. It reads excessive data. Use select directly to product_agg_tbl.

Power BI measure with filter affecting numerator and denominator differently

Building an accounting report, part of which is a ratio called "Receivables Turnover". It's calculated as "Sales" / "Trade Receivables". The calculation component of this is straight-forward (using CALCULATE), but I'm not able to wrap my head around how to filter this by date. Here's why:
The numerator - "Sales" - is filtered for the exact date i.e. "Get me the sum of sales in December 2018". However, the denominator of this calculation is filtered until the date i.e. "Get me the sum of trade receivables until December 2018".
So when I add a filter to the visual, it can be either filtered for the exact date OR filtered to be "on or before". How can I make it so that the numerator and denominator are impacted differently? Is this possible? If not, is there a way to workaround this?
I'm guessing each row of the receivable table contains a positive number for a debit or a negative number for a credit. In that case, the balance at a given point of time would be defined like below.
Receivable Balance =
CALCULATE (
SUM ( Receivable[Amount] ),
REMOVEFILTERS ( 'Calendar' ),
'Calendar'[Date] <= MAX ( 'Calendar'[Date] )
)
For example, if you drill-down the calendar to December 2018, this measure will show the total of all records on or before the end of December 2018.
Then you can use this measure to define the turnover ratio.
Receivables Turnover = DIVIDE ( [Sales], [Receivable Balance] )

Filter Dax Calculation based upon YTD Sum

In a Tabular SSAS Model, I'm trying to count the number of distinct customers that purchased a given product wtihin a YTD Timeframe. The table contains measures that aren't explicit sums, so I get the Cartesian Product of all products for each customer, regardless of no sales. I'm attempting to limit the count by filtering out customer / product combinations with YTD Sales = 0. However, I cannot get the FILTER to recognize the DATESYTD context. It only ever filters based upon Sales existing within the chosen calendar month. I've tried inserting the ALL function every which way.
This is what I have so far.
Measure:
CALCULATE (
DISTINCTCOUNT ( Fact[Customer] ),
DATESYTD ( Calendar[Date] ),
FILTER ( Fact,
CALCULATE ( [Sum of Sales], DATESYTD ( Calendar[Date] ) ) <> 0
)
)
This measure will, for example, count distinct customers purchasing a product in Month #5 if Month #5 is explicitly chosen. It will not, however, include a customer that purchased that item in Month #2 of the same year.
I think the following DAX should do the trick:
COUNTROWS(
FILTER(
VALUES(Fact[Customer]),
CALCULATE ( [Sum of Sales], DATESYTD ( Calendar[Date] ) ) <> 0
)
)
Also, make sure your 'Calendar' table has been marked as a date table. If, for some reason, you prefer not to mark it as a date table, rewrite the above DAX to:
COUNTROWS(
FILTER(
VALUES(Fact[Customer]),
CALCULATE ( [Sum of Sales], DATESYTD ( Calendar[Date] ), ALL('Calendar') ) <> 0
)
)
Edit: Do you have records in your fact table where [Sum of Sales] is 0? If not, then you could simplify and improve the performance considerably by writing:
CALCULATE(
DISTINCTCOUNT(Fact[Customer]),
DATESYTD( Calendar[Date] )
)
Again, if you haven't marked your 'Calendar' table as a date table, add ALL(Calendar) to remove the filter on specific calendar columns.

how to do a ranking of moving average in DAX

Assume there's a table T1 with columns [state],[product],[price],[store],[date], and a time table T2. There's a relationship between T2's [pk_date] column and T1's [date] columnit.
and I create a measure [5days moving average price]:
calculate
(
average('T1'[price])
,
DATESINPERIOD
(
'T2'[pk_Date],
LASTDATE ( 'T2'[pk_Date] )-1,
-5,
DAY
)
)
but for certain state and product, is there anyway I can get a rank of stores based on the [5days moving average price]? I tried something like
:=RANKX(ALLSELECTED('T1'[store]),[5Days Moving AVERAGE PRICE],,1)
but it didn't work.

Resources