woensdag 13 januari 2016

DAX : Building a monthly salesreport with estimation in PowerPivot (Part II)

Introduction

I'm not happy with the solution presented in my former post about Daily sales report because the current month is determined with the NOW() function. Rob Collie would say that the every time you look at a PowerPivot workbook you think: "that can be improved". The NOW() function calculates the current date like the GETDATE() function in SQL. This solution has some flaws, because when a user comes back months later and he or she wants to use this workbook again it won't work because the data is from months earlier. So, we have to think about a more robust solution.

When searching the web I was looking at the blogpost of Kasper de Jonge: "Use PowerPivot DAX to automatically report on the last month that has data" and he exactly covers this problem. In this blogpost I'll use this as a base for my solution.

MonthSelector

First I decided to add a monthselector slicer to my workbook. I changed the following code (the one with the NOW() function). I created this monthselector as calculated column in the Calendar dimension. This is the initial monthselector Dax expression.

=IF(
  MONTH(Calendar[CalendarDate]) = MONTH(NOW()) && 
  YEAR(Calendar[CalendarDate]) = YEAR(NOW()), 
  "Current Month",
  IF(
   MONTH(Calendar[CalendarDate]) = MONTH(EDATE(NOW(),-1)) && 
   YEAR(Calendar[CalendarDate]) = YEAR(EDATE(NOW(),-1)), 
   "Previous Month"
  )      
)

This is the final DAX expression:

=IF(
 Calendar[MonthNumber] = MONTH(LASTDATE(ALL(Sales[CalendarDate]))) && 
 Calendar[Year] = YEAR(LASTDATE(ALL(Sales[CalendarDate]))), 
 "Current Month",
 IF(
    Calendar[MonthNumber] = MONTH(EDATE(LASTDATE(ALL(Sales[CalendarDate])), -1)) && 
    Calendar[Year] = YEAR(EDATE(LASTDATE(ALL(Sales[CalendarDate])),-1)), 
    "Previous Month"
 )
)

I had to add a 'trick' to get it working. I added a RELATED() function in the Facttable to get the CalendarDate column. If I can remove this in the future I'll let you know..


And this is the result with the slicer in the PowerPivot.


Other improvements

Now let's take a look at the estimation DAX expression. As you may have read in my former blogpost, the estimation is the estimated sales for the rest of the month. This is now based on the Month to Date NetRevenue. This is also changed.

This is the DAX expression to determine the estimated sales amounts. As you can see the logic to determine the workingday - based on the a normal day in the calendar dimension- is removed. This automatically done by the PowerPivot engine. So, this is simplification with my initial solution.

SalesEstimation2:=CALCULATE(
                           DIVIDE([SalesAmountMTD] * [SUMWorkingDaysInMonth], 
                           MAX(Calendar[WorkingDayInMonth])
                                 )
                           ) 

The expression of the Month to Date Sales Amount :

SalesAmountMTD:=IF(ISBLANK([SalesAmount]), 
                  BLANK(),
                  Calculate([SalesAmount], DATESMTD(Calendar[CalendarDate])))   
 

This is the DAX expression of the SumWorkingDaysInMonth:

       
SUMWorkingDaysInMonth:=CALCULATE([NumOfWorkingDays], ALL(Calendar[CalendarDate]))
 

NumOfWorkingDays


NumOfWorkingDays:=CALCULATE([NumOfDays], Calendar[WorkingDay] = "Y")


This is the result for the previous month


And this is the result for the current month:



Conclusion

Everytime you work with DAX, you learn better ways with DAX to build your solutions. I'm working now a while with DAX expressions and every time you learn new tricks.

In this blogpost I've used a slicer based on the data in the fact and I've simplified my solution of the part I blogpost.

Greetz,
Hennie




zondag 10 januari 2016

DAX: The very long message "The semantic error or perhaps this error or this error.."

One day, I was working with a DAX expression in PowerPivot (Excel 2013) and I got the following error:

"Semantic error: The value for column 'Date' in Table 'dimCalendar' cannot be determined in the current context. Check that all columns in referenced in the calculation expression exist, and that there are no circular dependencies. This can also occur when the formula for a measure refers directly to a column without performing any aggregation -- such as sum, average, or count-- on that column. The column does not have a single value, it has many values, one for each row in the table, and now row has been specified."

Okay.. I prefer shorter messages normally and this error message popups in a tooltip and this tooltip disappears after a couple seconds. You have to move the cursor back and again and then you have a couple of seconds to read the tooltip again, before it disappears again. Well, I have written it all out in this blogpost and so you can read it at ease with a cup of coffee.

This was this the DAX expression that generated the error:

SumNetRevenue:=IF(MONTH(DimCalendar[Date]) = MONTH(NOW());
  SUM(FactCurrentMonthSales[NetRevenue]))
 

Now, the second part of the error is the interesting part and that said that there are different granularities in the expression. The SUM is on filtercontext but, the DimCalendar[Date] is on row level. I solved it with this DAX Expression:

SumNetRevenue:= IF(MONTH(MAX(DimCalendar[Date])) = MONTH(NOW()) ;
                 SUM(FactCurrentMonthSales[NetRevenue]))

Conclusion

Don't use very very long error messages in a tooltip ;-)

Greetz
Hennnie

dinsdag 15 december 2015

DAX : Building a monthly salesreport with estimation in PowerPivot (Part I)

Introduction 

In this blog post I would like show you step-by-step how to build a report in PowerPivot with DAX expressions. For my current customer I have to build a report that calculates the daily sales and a comparison with a budget. I've gathered the following requirements:
  • Calculate monthly sales to determine how much of this product has been sold per company, day and month.
  • Extrapolate monthly sales (estimation) and compare this with the budget.

The following restrictions are relevant here:
  • The working days must be taken into consideration.
  • Holidays must be taken in consideration.
  • The targets are monthly based.

This blog post is based on the paragraph entitled "Working days" from the book "The definitive guide to DAX" by Marco Russo and Alberto Ferrari.

The datamodel

A proper data model is designed with a sales fact table and a calendar dimension table. Rob Collie refers to these as data lookup tables and  data tables, but I prefer dimension and fact tables.

Calendar dimension 

For designing and filling the calendar dimension I would like to use a previous blogpost of mine in which I discuss building a calendar dimension in Excel. For this blogpost, I haveextended this example with the following fields:
  • DayInWeek : = WEEKDAY(B2)
  • WorkingDay : = IF(OR(WEEKDAY(B2)=1, WEEKDAY(B2)= 7), "N", "Y")
  • Holiday : Manually entered values Y for a holiday like Easter and N if not.
  • MonthNumber : = MONTH(1&LEFT(G10,3))

Below is a snippet of the calendar dimension where I included the holidays Easter and King's day (in the Netherlands).



This example was created with Excel but you can also generate this in SQL Server with a stored procedure for instance. This I would normally prefer.

Sales sample data

For example, I have created some sales data in the workbook. I have gathered some data for two months - March and May - because there are some holidays in these months and therefore it's possible to test the holiday scenario.


In this example, there are products sold on weekends and weekdays.

The PowerPivot data model

The next step is building the PowerPivot datamodel. This can do done by using CTRL-T of the table in Excel. Then give the table a name and add this to the data model. 


Don't forget to mark the calendar table as a date table in order to use time intelligence functions.


Building the measures

Normally, the next step would be to build the explicit measure layer in PowerPivot. In this layer the data source and the rest of the DAX expressions are separated from each other. But, for the sake of this example, I will not do that. I have created the following DAX Measures:

NumOfDays:=COUNTROWS(Calendar)

NumOfWorkingDays:=CALCULATE([NumOfDays], Calendar[WorkingDay] = "Y")

NumOfWorkingDaysIncHolidays:=CALCULATE([NumOfWorkingDays], Calendar[Holiday] = "N")

SalesAmount:=SUMX(Sales, Sales[SalesQuantity] * Sales[Unitprice])

DailySales:=DIVIDE([SalesAmount], [NumOfDays])

WorkDailySales:=DIVIDE([SalesAmount], [NumOfWorkingDays])

HoliWorkDailySales:=DIVIDE([SalesAmount], [NumOfWorkingDaysIncHolidays])    
 

These measures make a distinction between days, workingdays and holidays.

Let's take a look at the pivot table. For sorting the months I added an extra column in the calendar dimension MonthNumber (=MONTH(1&LEFT(G10,3))) and G10 is the Month name. Nice trick.



For instance, April has 30 days, of  which  22 are workingdays. However, when the holidays are subtracted we can see that there are really only 20 days for labor.

Now, let's take a look at the SalesAmount in the pivot table:


I have set the settings of the PivotTable to show the rows even when there is no data for a month. Now you can see that the Grand Total of Daily Sales is much lower than the average for April and May. If we divide 416.68 (the total annual sales) by 365 days we get 1.14, but that is not right. Thus it's better to divide it by something else. We have to neglect the days there was no data in the sales table.

       
NumOfDays:=IF([SalesAmount] > 0, COUNTROWS(Calendar))
 

But nothing happens. It only clears the values if you have a larger calendar dimension than I have. Marco Russo and Alberto Ferrari call this a "granularity mismatch" in their book "The Definitive Guide to DAX". The numbers are accurate at the month level but inaccurate at the Grand Total level. The problem is how to determine the right granularity level. This is a business rule and it depends on how you build the pivot table in your report.

We have to use an iterator: SUMX and SUMX iterates over the values and sums them by a certain level of granularity. In my case I would like to use a monthly granularity.

DailySales:=DIVIDE([SalesAmount], SUMX(VALUES(Calendar[MonthName]), [NumOfDays]))

WorkDailySales:=DIVIDE([SalesAmount], SUMX(VALUES(Calendar[MonthName]),[NumOfWorkingDays]))

HoliWorkDailySales:=
DIVIDE([SalesAmount], SUMX(VALUES(Calendar[MonthName]),[NumOfWorkingDaysIncHolidays])) 
 

And this results in the following pivottable:


And I manually calculated the Grand Total of the Sales measures and the numbers are correct.


So where are we now?

In the beginning of this blog post I listed gathered some requirements. Let's see what we have done so far:
  • Monthly sales. How much have we sold of this product or per company.
  • Extrapolate of monthly sales and compare this to the target.
  • Take the working days in consideration.
  • Take the holidays in consideration.
  • The targets are monthly based.
In the next section I would like to give some thoughts on extrapolation of the current month sales, This way we can determine whether the monthly sales targets and actual sales are on target.

Estimated Sales

For this reason, I have entered some extra data to the Sales table until 'today'.


Furthermore, I have added an extra column to the Calendar dimension, WorkingDayInMonth and this is a running number in the Calendar dimension that is raised by 1 of the day is a working day and not a holiday. Below is an example from the month December for which I have added some test data for the WorkingDayInMonth column.


By doing so, I can lookup the current working day that depends on the current day of the month. For instance, it's now December 14th and the current working day is 11. It is now possible to calculate the sales amount that is earned by the company and then calculate the extrapolated sales amount for the working days left in the current month.

I have added some extra measures to the Power Pivot workbook.

Today:=DATE(YEAR(NOW()),MONTH(NOW()),DAY(NOW()))

WorkingToday:=LOOKUPVALUE(Calendar[WorkingDayInMonth], Calendar[CalendarDate], Calendar[Today])

SalesEstimation:=IF(MONTH(NOW()) = MAX(Calendar[MonthNumber]), 
 DIVIDE(([SalesAmount] * [NumOfWorkingDaysIncHolidays]), [CurrentWorkingToday]),[SalesAmount]) 

The measure 'Today' is used by the other measure 'WorkingToday' for looking up in the Calendar dimension. The WorkingToday is the current working day in the current month. Perhaps you would like to limit this measure by the current month scope, but I will leave that up to you.

The measure SalesForecast calculates the estimated sales in the current month by using the following pseudo-formula:

EstimatedSales = SUM(SalesAmount/WorkingDaysSofar x NumOfWorkingDaysIncHolidays)

And this is the result of the calculation (I renamed SalesForecast to SalesEstimation):


At this point there is only one problem and that is the SalesEstimation on the Grand Total level.

In order to avoid confusion,  I added an extra IF to the measure :

SalesEstimation:=
IF(COUNTROWS(VALUES(Calendar[MonthNumber])) = 1, 
  IF(MONTH(NOW()) = MAX(Calendar[MonthNumber]), 
 DIVIDE(([SalesAmount] * [NumOfWorkingDaysIncHolidays]), [CurrentWorkingToday]),[SalesAmount]),
 BLANK()
)

Resulting in



Conclusion 

This blog post describes an implementation of a Daily Sales Report for a month with an estimation of sales amount in the current month.

Greetz
Hennie

maandag 14 december 2015

Windows 10 : We couldn't update the system reserved partition

Introduction

Today, I thought it was a good idea for upgrading my laptop from Windows 7 to Windows 10. I neglected the upgrade pop up window for too long now. Let's do it! Well, that's not as easy as I expected upfront because of this error message: "We couldn't update the system reserved partition". I'm not sure but on some sites I've read that it could be the result of migration from HDD to SSD with the Samsung migration software.

In this blogpost I'll describe the problem, the solution and the conclusion.

The error message

In my particular case I recieved the following error: "We couldn't update the system reserved partition." and this is depicted below:


I opened Disk Management and I saw the following information:


In this screenshot the data volume is a System Primary Partition and I assumed that this one is the one with the problem. It's only 1% free and it's a system partition.

The solution

1. I installed the Minitool Partition Wizard 9.1 Free edition.



2. And launched the application:


And here you can see the Active & Boot partition. In my case it is named "Data" but I've also seen sites where the partition is named RECOVERY.

3. Resize the C partition in order to make some space free (I found out later that this not really needed. You can grab some free space from C:).


4. The result of this step.


5. Now, extend the system reserved partition to the desired amount.


And now the final result should be this (depicted below):


The system reserved partition is now enlarged to 300 MB.

6. The next step is to apply the settings


After some nail biting restarting, flickering and a progress bar that stops sometimes, the volume is enlarged to 300 MB.


And the installation of windows 10 succeeded without any problem.

Conclusion

I think that the migration from HDD to SSD of the Samsung software changed something in the reserved partition.

Greetz,

Hennie

zondag 13 december 2015

DAX: Using DAXStudio for building DAX expressions

Introduction

I was wondering how I could improve building DAX expressions and one way to do that is by using DAX Studio. DAX Studio gives you a richer developer experience than the standard DAX expression editor in PowerPivot.

On the blog of Marco Russo on SQLBlog.com you can find more information about using DAX Studio for building DAX expressions.

Define Measure

In order to use this technique you have to use the following pattern to make it work:

1. Define the measure.
2. Use this measure in you calculation.

Here is an example:

  
DEFINE MEASURE Sales[MTDInvoicedSales] = CALCULATE([TotalInvoicedSales], DATESMTD(Calendar[Date]))
EVALUATE
SUMMARIZE (
Sales,
Calendar[YYYYMM],
"InvoicedSales", Sales[MTDInvoicedSales]
)
 

And below depicted in a printscreen:


Conclusion

Use DAX studio when you are developing DAX Expressions with PowerPivot in Excel.

Greetz,
Hennie