I've got two primary datasets:
Real data with all sales transactions.
For example RealData:
Date;Sales
16-01-2017;1200
20-01-2017;1500
05-02-2017;800
08-02-2017;1100
13-02-2017;300
Etc.
A plan with total sales I want to achieve, with totals at the last day of each month.
For example EndOfMonthTargets:
Date;Sales
31-01-2017;3000
28-02-2017;2500
Etc.
In my real data I (a) also have data from the years before 2017, and obviously I have the targets for each month in 2017. The RealData is always live / up to date.
What I'm trying to do is show KPI visualizations: how is the real data vs the plan doing. However, I can't figure out how to relate the two datasets, because the cannot really be joined together.
What is the idiomatic way to do this in PowerBI?
I've tried:
adding a column to each source with its respective status ("real" vs "plan")
creating a union (i.e. "Append Queries as New")
adding a column Month = MONTH([Date])
Giving me this data:
But that's weird, because then the KPI visualization will include the "Plan" data either at the start or worse at the end where it will be plotted as the "current" number.
The expected output is a KPI visualization:
showing the absolute number of sales summed by year (or month, if my slicers are set that way!)
with the Target goals retrieved from the plan data
with a trend based on previous years (not included in my sample data)
How do I achieve that?
There are a few ways to join tables like this. What you have are 2 tables with different granularities: a sales table that goes to the day, and a target table that goes down to the month. It's a common request to model them against each other, and it boils down to having a lookup table that both fact tables can join with.
What I would recommend:
Have a table of your real data
Have a table of your plan/target data, using the last day of the month is fine
Do not relate these 2 fact tables together directly
Rather, have a separate date lookup table, to which both tables are joined. This date dimension should, at a minimum, have a month & year column (e.g. March 2017).
Join both fact tables to your date table
Hide the date fields in your 2 fact tables, so that you aren't tempted to use them in visuals (you have to use the date fields from the lookup table instead)
You can then create measures to SUM your actual and targets. And then additional measures that subtract those 2 measures against each other (or divide one into the other). All those measures will then be sliceable by the month & year on your date table. (You could slice them by date too, but because targets are assigned to the last day of the month, that granularity will be less than helpful.)
There's a lot of good information & examples here: http://www.daxpatterns.com/handling-different-granularities/
The way I would do it:
Add a calculated column to both real and targets tables:
Month = Date(Actual[Date].[Year],Actual[Date].[MonthNo],1)
Month = Date(Target[Date].[Year],Target[Date].[MonthNo],1)
Create relashionships between these
Plot SUM(RealData[Sales]) and Target[Sales] against Target[Month]
You can use PowerQuery to transform data.
"Real" table:
let
Source = Table.FromRecords({[Date="16.01.2017", Sales = 1200], [Date="20.01.2017", Sales=1500], [Date="05.02.2017", Sales = 800], [Date="08.02.2017", Sales = 1100], [Date="13.02.2017", Sales = 300], [Date="10.01.2016", Sales = 1400], [Date="02.02.2016", Sales = 1800]}),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Sales", Int64.Type}})
in
#"Changed Type"
"Plan" table:
let
Source = Table.FromRecords({[Date="31.01.2017", Sales = 3000], [Date="28.02.2017", Sales=2500], [Date="31.01.2016", Sales = 2800], [Date="29.02.2016", Sales = 2700]}),
#"Changed Type" = Table.TransformColumnTypes(Source,{{"Date", type date}, {"Sales", Int64.Type}})
in
#"Changed Type"
Your query for getting data, let's name it GetData:
let
t1 = Table.AddColumn(Real, "Source", each "Real"),
t2 = Table.AddColumn(Plan, "Source", each "Plan"),
MergedTable = Table.Combine({t1, t2}),
AddYear = Table.AddColumn(MergedTable, "Year", each Date.Year([Date])),
AddMonth = Table.AddColumn(AddYear, "Month", each Date.Month([Date])),
Group = Table.Group(AddMonth, {"Year", "Month", "Source"}, {{"Sales", each List.Sum([Sales]), type number}})
in
Group
You may avoid using last step by grouping results at report level, but this will result in users being able to view amount of each sale. If this is expected behavior, just remove Group step, or replace it with Table.RemoveColumn to remove [Date].
If you need separate columns for Plan and Real values, then pivot Source column.
Then just use GetData query in clustered column chart.
You will have to create a measure to calculate the Actual total and measure to calculate the Planned by each month or end of month. Then create a measure to compare the difference between Planned total and Actual total.
Actual =
CALCULATE (
SUM ( RealDate[Sales] ),
FILTER (
ALL ( RealDate ),
MONTH ( [Date] ) = MONTH ( MAX ( EndOfMonthTargets[Date] ) )
&& YEAR ( [Date] ) = YEAR ( MAX ( EndOfMonthTargets[Date] ) )
)
)
Planned = SUM(EndOfMonthTargets[Sales])
ActualVSPlanned = [Actual] - [Planned]
Now use that measures and the Date in eEndOfMonthTargets table to build a matrix:
For the ActualVSPlanned measure use conditional formating as follows:
You will get something like this:
Related
A little bit of background: I'm trying to figure out how to substract two measures (provided below) from each other to be displayed in a table portraying the change based on the different dates. Please check out the picture for a bit of introductory context.
So far I've succeeded in creating the correct measures for calculating all of the 'trades' made up to a specific trade date, while also filtering the trades with a maturity date only from that specific trade date onwards.
The two measures below are nearly identical and only differs by using other date tables so I am able to select for each of my two slicers. In the beginning I had only one measure, and would just 'Edit interactions' for the two tables provided by the picture, but I duplicated it all to create another slicer because I thought I could just subtract two measures and be done with it.
Measure 1:
TRADES_MEASURE =
VAR ReferenceDate = [MaxSelectedDate]
VAR PreviousDates =
DATESINPERIOD(
'Previous Date'[Date],
ReferenceDate,
-18,
YEAR)
VAR FutureDates =
DATESINPERIOD(
'Maturity previous date'[Date],
ReferenceDate+1,
50,
YEAR)
VAR Result =
CALCULATE(
COUNT('INTEREST TRADES'[TRADEID]),
REMOVEFILTERS('Date'),
KEEPFILTERS(PreviousDates),
REMOVEFILTERS('Maturity date'),
KEEPFILTERS(FutureDates),
USERELATIONSHIP('Date'[Date],'Previous Date'[Date]),
USERELATIONSHIP('Maturity date'[Date], 'Maturity previous date'[Date]))
Return
Result
Measure 2:
TRADES_MEASURE_2 =
VAR ReferenceDate = [MaxSelectedDate 2]
VAR PreviousDates =
DATESINPERIOD(
'Previous Date 2'[Date],
ReferenceDate,
-18,
YEAR)
VAR FutureDates =
DATESINPERIOD(
'Maturity previous date 2'[Date],
ReferenceDate+1,
50,
YEAR)
VAR Result =
CALCULATE(
COUNT('INTEREST TRADES'[TRADEID]),
REMOVEFILTERS('Date 2'),
KEEPFILTERS(PreviousDates),
REMOVEFILTERS('Maturity date 2'),
KEEPFILTERS(FutureDates),
USERELATIONSHIP('Date 2'[Date],'Previous Date 2'[Date]),
USERELATIONSHIP('Maturity date 2'[Date], 'Maturity previous date 2'[Date]))
Return
Result
Solution request
If I attempt to create a measure that simply subtracts the two measures It doesn't perform the calculation correctly because I have two date slicers it needs to take into account. For instance if I select both date slicers to 'Interact' with the table it doesn't seem to calculate it correctly when I make a simple measure performing 'Measure 1 - Measure 2'.
Visually I just need the calculation: 'Table 1'[AMOUNT] - 'Table 2' [AMOUNT], but the way my measure is setup makes it a bit more complicated.
Visual: Tables
Solved!
I realised that by simply adding
REMOVEFILTER('Date 2')
REMOVEFILTER('Maturity previous date 2')
to the CALCULATE function in Measure 1 and likewise
REMOVEFILTER('Date ')
REMOVEFILTER('Maturity previous date')
to the CALCULATE function in Measure 2, it then successfully took into account both of the slicers without filtering dependent on only one slicer.
Cheers!
I am using power BI and I would like to create a line chart which contains values from two tables (sales history and sales prediction). So for the past 12 months, the line should reprensent the sales history and for the next 6 months, the line reprensents sales prediction. Here is what the data looks like, lets say we are in June 2021:
I know there is a way to do it in DAX but I don't know how to do it by myself. Thanks a lot in advance for your help !
You can achieve this by
Delete any relationship between Calendar and the other two tables if there is any, as we are going to use DATESBETWEEN function to calculate
Create two metric like below, you might need to adjust the column names as per your project
Sales History Amount = IF('CALENDAR'[Date] <= TODAY(), CALCULATE(SUM('Sales History'[Amount]), DATESBETWEEN('Sales History'[Date], MIN('CALENDAR'[Date] ), MAX('CALENDAR'[Date]))), BLANK())
Sales Prediction Amount = IF('CALENDAR'[Date] >= TODAY(), CALCULATE(SUM('Sales Prediction'[Amount]), DATESBETWEEN('Sales Prediction'[Date], MIN('CALENDAR'[Date] ), MAX('CALENDAR'[Date]))), BLANK())
Add these two metrics in the table and use the Date from the Calendar table as X axis.
Format the first metric to solid line, and dash line for the second
Calendar should be linked to your tables.
Prediction Amount =
VAR lastSalesDate = MAX('Sales History'[Date])
VAR currentPredictionAmnt =
CALCULATE(
SUM('Sales Prediction'[Amount])
,KEEPFILTERS('CALENDAR'[Date]>lastSalesDate)
)
RETURN currentPredictionAmnt + SUM()
Sales Amount =
SUM('Sales History'[Amount])
Can someone help me to transfer this code to Power Query. I found this one in dax, but I would prefer to have it done already in the data transformation.
Avg Activation Time =
var Oppy_id = 'Calculation'[Reference number]
Return
AVERAGEX(
FILTER(ALL('Calculation'), 'Calculation'[Reference number] = Oppy_id),
'Calculation'[Activation (wd)])
Without examples of your data and desired output, it is not possible to be more specific, but this should get you started.
In PQ to average values that are linked to a particular group (ID), you would GroupBy the ID, and select Average for the aggregation (with Activation Days for the Value column.
In M, it would look generally like:
#"Grouped Rows" = Table.Group(#"Previous Step", {"ID"}, {
{"Average Activation Days", each List.Average([Activation Days]), type nullable number}
}),
In your code, the step would have different references for the previous step, and possibly for the column.
I need to create a calculated column that is based on another column but depends on the date filter the report is run for.
If the item is own for more than a year it is 'Comparable' if less than a year it is 'Non Comparable'.
I have Item, DateOfPurchase in T1 and Date in T2 (Period table)
I have come up with DAX using today() but it only works if we report on today's date.
This didn't work (no idea why)
=if( dateadd( 'Item'[PurchaseDate],1,year)<today(),"Comp","Non-Comp")
This worked but only for current period
=DATEDIFF('Item'[PurchaseDate],today(),MONTH)
= if('Item'[DateDiff]>12,"Comp","NonComp")
However, I can not use that column when running report for a different period, because attribute is not valid for prior periods.
Since calculated columns are computed only once, when the table is processed/refreshed, you cannot use a calculated column for your scenario.
Instead, consider using a disconnected parameter table. In your case, this would be a table with 1 column and just 2 rows: "Comp" and "NonComp". You can create this as a calculated table like so:
ParameterTable = DATETABLE("Value", STRING, {{"Comp", "NonComp"}})
Based on what the user selects on this table - which you can find using SELECTEDVALUE(ParameterTable[Value]) - you apply the relevant logic in a measure instead:
BaseMeasure =
// Whatever you are trying to calculate
SUM(Item[Amount])
Measure =
// This measure will respect the user selection (Comp / NonComp) and the current period:
VAR compValue = SELECTEDVALUE(ParameterTable[Value])
VAR today = MAX('Date'[Period])
RETURN
SWITCH(
compValue,
"Comp", CALCULATE( [BaseMeasure] , DATEDIFF('Item'[PurchaseDate], today, MONTH) > 12),
"NonComp", CALCULATE( [BaseMeasure] , DATEDIFF('Item'[PurchaseDate], today, MONTH) < 12),
[BaseMeasure] // Fallback, in case user didn't select Comp/NonComp
)
If you have multiple base measures in your report, you will need to implement this pattern for each of your base measures.
We have requirement to allow user to choose which currency he wants to see in the dashboard, like below example:
By default, it's GBP, if user changes to USD, we need to show the spend by USD. Under the hood we already have table InvoiceDetail which contains columns doing currency conversion beforehand:
SpendInGBP
SpendInUSD
SpendInEUR
I am not sure how I can map when user chooses different currency using ChicletSlicer to different Columns.
If you have a table containing all formats available to apply this can be achieved.
I've created these tables as example:
MyTable
CurrencyFormat
In the MyTable table I've created two measures called Format and Total Sales.
Format = LASTNONBLANK ( CurrencyFormat[Format], 1 )
Total Sales = Total Sales = FORMAT(SUM(MyTable[Sales]),[Format])
Note Total Sales measures uses the [Format] measure to get the selected format from the slicer.
Adding the ChicletSlicer and setting FormatName column from CurrencyFormat table in Category pane, you should get the expected result.
Also note the formats I've used can vary from what you need, so you have to add some changes to the format strings, do a quick read of the documentation about it.
Format Region
$#,##0;($#,##0) SpendInUSD
£#,##0;(£#,##0) SpendInGBP
€#,##0;(€#,##0) SpendInEUR
UPDATE: OP wants to get the sum of the right column based on the slicer.
Fortunately your table has a column for every currency, as you found with my proposal to map the slicer value to your measure, this is the final expression:
Spend =
IF (
LASTNONBLANK ( 'Currency'[Code], 1 ) = "GBP",
SUM ( Invoice[SpendGBP] ),
IF (
LASTNONBLANK ( 'Currency'[Code], 1 ) = "USD",
SUM ( Invoice[SpendUSD] ),
SUM ( Invoice[SpendEUR] )
)
)
Let me know if you need further help.