Introduction
to my final article, about constructing the Like-for-Like (L4L) answer primarily based on Energy Question:
The answer works as anticipated for probably the most half. I confirmed it to my friends and to some purchasers.
The suggestions was constructive, however I’ve received some questions, and the outcomes of my answer weren’t what the individual asking anticipated.
The problem
I found a problem whereas calculating the PY worth.
Technically, the outcomes are right, however they aren’t from a consumer perspective.
Take a look at the next two screenshots, which present two completely different instances that embody the Retail Gross sales and the Retail Gross sales PY measures. The outcomes for these two instances can confuse the viewers.
Attempt to spot the difficulty earlier than persevering with to learn.
That is the primary case for the Torino retailer, which was briefly closed between March and July 2024.

And right here is the second case for the Roma retailer, which was briefly closed from August to October 2023 and completely closed in August 2024.
We see these outcomes for the second case:
- The values for the Retail Gross sales PY measure for “Comparable” shops, however with an interruption between August and October.
- Values for the Retail Gross sales measure for “Non-Comparable – Closing” shops.
- Values for the Retail Gross sales PY measure for “Non-Comparable – Refresh” shops.
From a technical perspective, these outcomes make absolute sense and are right.
The measures present the proper L4L States for the present interval and the earlier yr.
So, what are the problems?
For the consumer, they’re very complicated and won’t match expectations.
Give it some thought from the consumer’s perspective:
When outcomes for particular L4L states, the 2 measures ought to assign outcomes to the identical L4L state, no matter whether or not they’re calculated for the present interval or the earlier yr.
This introduces a brand new complexity to the answer.
The answer
I want a second column for the L4LKey for the earlier yr.
For the primary L4LKey column, I evaluate the opening and shutting dates to the month-to-month dates of the earlier yr (See the primary article for the small print).
For the second L4LKey_PY column, I need to evaluate these dates to the month-to-month dates of the identical yr because the opening and closure dates.
The concept is considerably counterintuitive, but it surely delivers the end result I want.
Please stick with me, and you will notice the way it pans out
First, I attempted fixing it in Energy Question, as I did within the unique answer. Nevertheless it didn’t work. I’ll come to the explanation in a minute.
Then, I switched to constructing the Bridge_L4L desk in SQL, however the outcomes had been unusable once more, as I all the time received duplicated rows for the Rome retailer, as I’ve two rows for the 2 L4L-states for this retailer:

I’ve one row every for the momentary closure in 2023 and the definitive closure in 2024.
Subsequently, the be part of all the time returns two rows, as the shop key’s duplicated.
So, I made a decision to modify to a procedural strategy.
I loop by way of every row within the desk containing the opening and shutting shops and apply the states to the desk, which has one row per retailer and month.
I did this by utilizing momentary tables in SQL and the next SQL code:
-- Declare all wanted variables
DECLARE @StoreKey int;
DECLARE @OpenDate date;
DECLARE @CloseDate date;
DECLARE @L4LKey int;
-- Create the Cursor to loop by way of the Shops with every opening, closing, and refresh dates
DECLARE sd CURSOR FOR
SELECT [StoreKey]
,[OpenDate]
,[CloseDate]
,[L4LKey]
FROM #tmp_Store_Dates
-- Order per Deadline, because the process should run from the primary (oldest) to the final (latest) row
ORDER BY [CloseDate];
OPEN sd;
-- Get the primary row
FETCH NEXT FROM sd INTO @StoreKey, @OpenDate, @CloseDate, @L4LKey;
-- Begin the loop
WHILE @@FETCH_STATUS = 0
BEGIN
-- Replace all rows in response to every retailer primarily based on the L4L standing and the respective dates, primarily based on the earlier years' dates
UPDATE [#tmp_Stores_Months]
SET [OpenDate] = @OpenDate
,[CloseDate] = @CloseDate
,[L4LKey] = CASE @L4LKey
WHEN 2
THEN IIF(@OpenDate >= [FirstDayOfMonthPY], @L4LKey, NULL)
WHEN 3
THEN IIF(@CloseDate <= [LastDayOfMonthPY], @L4LKey, NULL)
WHEN 4
THEN IIF(@OpenDate >= [FirstDayOfMonthPY] AND @CloseDate <= [LastDayOfMonthPY], @L4LKey, NULL)
ELSE 1
END
WHERE [L4LKey] IS NULL
AND [StoreKey] = @StoreKey;
-- Replace primarily based on the identical month for the PY calculation
UPDATE [#tmp_Stores_Months]
SET [OpenDate] = @OpenDate
,[CloseDate] = @CloseDate
,[L4LKey_PY] = CASE @L4LKey
WHEN 2
THEN IIF(@OpenDate >= [FirstDayOfMonth], @L4LKey, NULL)
WHEN 3
THEN IIF(@CloseDate <= [LastDayOfMonth], @L4LKey, NULL)
WHEN 4
THEN IIF(@OpenDate >= [FirstDayOfMonth] AND @CloseDate <= [LastDayOfMonth], @L4LKey, NULL)
ELSE 1
END
WHERE [L4LKey_PY] IS NULL
AND [StoreKey] = @StoreKey;
-- Get the subsequent row till all rows are processed
FETCH NEXT FROM sd INTO @StoreKey, @OpenDate, @CloseDate, @L4LKey;
END
-- Shut the Cursor
CLOSE sd;
DEALLOCATE sd;
-- Replace the L4LKey and L4LKey_PY in all empty rows
UPDATE #tmp_Stores_Months
SET [L4LKey] = 1
WHERE [L4LKey] IS NULL;
UPDATE #tmp_Stores_Months
SET [L4LKey_PY] = 1
WHERE [L4LKey_PY] IS NULL;The results of the process is a desk containing one column mapping the L4L states primarily based on the earlier yr for every month (L4LKey) and one column mapping the L4L states primarily based on the identical yr for every month (L4LKey_PY):

The subsequent step is to import the end result for this process into Energy BI and add an extra relationship between the Bridge_4L and the DIM_L4L desk for the brand new L4LKey_PY column:

This enables me to manage the calculation for the PY end result.
Retail Gross sales (PY) =
CALCULATE([Retail Sales]
,'Time Intelligence'[Time Measures] = "PY"
,USERELATIONSHIP('Bridge_L4L'[L4LKey_PY], 'DIM_L4L'[L4LKey])
)Now, the outcomes are what is anticipated.
Right here, the primary case:

And listed below are the outcomes for the second case:

As you may see, the PY values are assigned to the identical L4L state because the current-year outcomes.
Now, the consumer sees constant outcomes, that are a lot simpler to know.
Conclusion
The extra name of the USERELATIONSHIP() perform might be put in a Calculation Merchandise and utilized by all PY measures.
This makes it very simple to make use of with none extra DAX logic.
Anyway, this problem was comparatively simple to unravel. However after I thought-about a Month-over-Month calculation with the L4L performance, I spotted it wouldn’t be potential with out some DAX code. Presumably, I’ll dig into this in a future article.
However this case emphasizes the necessity to use the consumer’s perspective when designing and testing an answer.
It isn’t sufficient to make use of a technical perspective; the consumer’s perspective is far more necessary when evaluating the answer’s performance and outcomes.
For me, this was a really attention-grabbing expertise and really helpful for my future work.
I hope that you simply discover my strategy attention-grabbing. Keep tuned for my subsequent piece.
References
That is my earlier article on this subject:
Right here is the SQLBI article concerning the like-for-like sample with a DAX answer primarily based on model-independent UDFs.
Like in my earlier articles, I take advantage of the Contoso pattern dataset. You’ll be able to obtain the ContosoRetailDW Dataset totally free from Microsoft right here.
The Contoso Information can be utilized freely underneath the MIT License, as described on this doc. I up to date the dataset to shift the info to modern dates and eliminated all tables not wanted for this instance.



