Sales/Budget: Integrating Data of Different “Grains”

January 12, 2012

 
image

Latest Article for CIMA Insight

Some of you know that I’ve been writing a series of articles for the Chartered Institute of Management Accounts, aka CIMA.  Up until this point those articles have either focused on the organizational impact, the “why” of PowerPivot.  Things like how it contrasts with traditional BI and traditional spreadsheets.  How it saves costs and delivers more.

And then I started to introduce basic topics that have already been covered at length here on this blog, just simple how-to-get-started stuff.

But this month is the first time I wrote something for CIMA that I have not really covered here.

The Problem:  60k Sales Rows vs. 2k Budget Rows

PowerPivot Sales Data Very Granular Day Level

Sales Table with 60 Thousand Rows

PowerPivot Budget Table Less Granular Month Level

Budget Table with Two Thousand Rows

The Desired Result:  A Single Unified Report

PowerPivot Report Combining Day Level Actual Sales and Month Level Budget Granularities

The Solution

Diagram of How to Integrate Different Granularities of Data in PowerPivot

Here’s where I have simplified it a bit for the introductory audience.  I likely have a Calendar table in a well-designed model, and that doesn’t appear in the diagram.  I also likely have to solve for more than just Time granularity – the Budget is also likely less granular at the Product level as well.

But to introduce this powerful concept, I think a simple example is best so I kept it clean.

Click here to read the full (short) article and see the details of how I create the linkage between the two tables.

Popular Topic This Month!

Everyone has this on the brain this month it seems Smile

First, in the exact same issue of CIMA, there’s an article about handling Sales vs. Budget using traditional Excel.

And Marco Russo has written one about this same topic in PowerPivot and BISM Tabular.  As usual, his approach is excellent, and quite different from what my more primitive mind conjures.

I didn’t even have to use the Boot Signal:


In the Browser, Aesthetics Yield a Greater Return

January 10, 2012

 

A PowerPivot Doc in the Browser is an Application   
A Spreadsheet in Excel Services Is No Longer a Document,
It’s an Application

I thought today was going to be a “handful of mini posts” kind of day but then this post blossomed into a bit more than I thought it would, which is a good thing.

Normal Spreadsheets are Usually Ugly and That’s OK

It’s true:  most Excel pros are not artists.  I certainly am not.  We’re number folks first and foremost, and our jobs haven’t historically placed top-level emphasis on aesthetics either.  So we don’t spend much time on it, typically.

Besides, Excel itself isn’t pretty.  Back in the 80’s or 90’s, even if you made a spreadsheet look fantastic, well, it was still loaded in Excel.  So you got all those lovely “battleship grey” toolbars, the title bar, etc.:

Spreadsheets of Yore Were Also Made Ugly Just by the Excel Frame

Spreadsheets of Yore Were Also Made Ugly
Just by the Excel Frame Itself

I want to be clear:  This is NOT a post that is going to encourage you to run out and start putting lipstick on all of your spreadsheets. 

Instead, I am going to make the case for why the game changes significantly (for the better too) when you switch to using a server (or a cloud hosting service like ours) to share your work.

The “Excel Frame” Has an Enormous, Underappreciated Impact

Hey, you might say that the old-style Excel screenshot above is an unfair example, since Excel 2007 and 2010 replaced menus and toolbars with the Ribbon.  But in a crucial way the Ribbon is NO different really – the point is that either way (ribbon or menu/toolbars) the Excel frame is NOT YOURS.  It belongs to Excel.  And no matter how much work goes into the document itself, the user of that document still thinks you made them a document.

Let that sink in for a minute.  Because the user of your spreadsheet thinks they are “using Excel” and not “using an application built by my favorite Excel pro,” you are receiving a hidden benefit AND a hidden penalty:

  1. There are many things you will never be blamed for as long as the consumer thinks of Excel as the application.  Hey, the overall experience just feels kinda clunky.  “No big deal, that’s just how Excel docs always are.”
  2. But you also don’t get nearly enough credit, psychological impact, or perceived importance that your work deserves.  Seriously, your work drives your organizations.  If everyone thought of you as a programmer (which you are, even if you don’t write macros), you’d be viewed differently.  But people who produce documents are often viewed as “Excel Monkeys.”  Honestly I think Excel pros are, for the most part, underpaid relative to their true importance.

When you switch from mailing spreadsheets around to publishing spreadsheets on SharePoint, well, both of those go out the window.  Well, if you do it right, anyway.

SharePoint Brings Its Own Frames!  Ack!

OK, so you switch over to using SharePoint as your publishing mechanism.  Does that get rid of the Excel frame?  Well not really.  It just gives you a new Excel frame in your browser:

See all of those highlighted elements?  Just another Excel frame, ported to the browser.  Complete with File tab, toolbar, the .XLSX extension blazoned across the top, and even a warning bar.

Not to be left out, SharePoint adds some of its own at times:

So, you gotta get rid of those.  And that means customizing SharePoint.  If you’re a SharePoint pro that’s mostly not too difficult, but even then it likely will take you some time to get it tuned just right (we’ve been making tweaks now for two years).  And if you’re not a SharePoint pro, well, you are going to need one.

(For more info on the details of these SharePoint elements and what we’ve done to modify/suppress them, see this post and this post).

Going Frameless Turns “Document” Into “Application”

In our Hosted PowerPivot offering, we’ve got all of that suppressed, and the only “frame” you see is just the browser and a typical web header.  An example:

PowerPivot Application Built by Pivotstream

The Consumers of This Application Neither Know NOR Care that it Was Built in Excel

The idea for this post struck me yesterday as I was putting together this sample workbook (based on Microsoft’s AdventureWorks data set) that we are going to start including in all of our HostedPowerPivot sites as a tutorial:

Sample Hosted PowerPivot Workbook

Sample Workbook v1 For Hosted PowerPivot

Or try this humorous example (based on real data) that examines UFO sightings – click image to view the application on Mr. Excel’s HostedPowerPivot site.

Live PowerPivot Application on HostedPowerPivot

Click Image to View the Live APPLICATION

Completing the Illusion:  A Few Simple Steps

Once you’ve gone frameless, there are a few simple things you can do to complete the transformation from document to application.  Neglect these and your “frameless” would-be application screams “spreadsheet” to the audience.  Follow them, and even if you’re not terribly artistic, your work will be perceived very differently:

  1. Turn off gridlines and headers.  It’s not hard.  Two checkboxes on the View tab of the ribbon, but do that for EVERY sheet the consumer sees.  Every single one.  Crucial.
  2. Hide or delete all sheets you don’t want them to consume.  Don’t leave extra blank tabs in there named “Sheet3” OK?
  3. Insert some images.  So important!  Your company logo.  Your client’s logo.  Something.  And make sure you use the Insert ribbon to do this!  Simple copy/pasting an image into a worksheet, in my experience, seems to result in that image NOT showing up in the browser.
  4. Line up slicers, charts, and tables.  Takes just a minute or two to make sure the top of your slicers are even with the top of your chart, etc.
  5. Don’t neglect number formatting.  If something is a currency, format it as a currency.
  6. Use conditional formatting.  No need to overdo it, but conditional formatting turns a boring black and white grid (a pivot) into an inviting surface that is actually fun to look at.  Plus, trends, patterns, and outliers jump off the page much more readily.  I’m especially fond of data bars, color scales, icon sets, and when I have the time, sparklines.
  7. Create a Menu sheet (Table of Contents), and use hyperlinks for navigation.  Yes, the sheet tabs are visible.  But why force people to use them?  There are a million reasons why sheet tabs are disproportionately old fashioned and cognitively difficult.  When it comes to navigating around a web application,  nothing comes close to a hyperlink. 

“I’ll Take ‘Hyperlinks Between Sheets’ for the Win”

Let’s focus on that last one.  Did you know that you can hyperlink between sheets in a workbook?  I worked on Excel for years and never really realized this.  Our CEO at Pivotstream pointed that out to me, and it works on the server too.

Hyperlinking Between Sheets in Excel

Hyperlinking Between Sheets in Excel

This lets you create menu sheet like the AdventureWorks sheet above, as well as this one at the beginning of the post:

This Is Actually a PowerPivot Menu Sheet aka Table of Contents

This Is Actually a PowerPivot Menu Sheet (aka Table of Contents)

Cool huh?  Those chart thumbnails are IMAGES.  The hyperlinks above them take you to the full-page interactive sheets that host each of those chart views.

Formatting Macros

I have a number of macros that help me do some of this stuff, and in an upcoming post I will share some of them, once I have time to organize them a bit.

In the meantime, here’s a real simple one whose intent should be obvious:

Sub HideGridAndHeadersOnAllSheets()

    Dim oSheet As Worksheet
   
    For Each oSheet In ActiveWorkbook.Worksheets
        If oSheet.Visible = xlSheetVisible Then
            oSheet.Activate
            ActiveWindow.DisplayGridlines = False
            ActiveWindow.DisplayHeadings = False
        End If
    Next

End Sub

How many of you use macros, by the way?  I’m really curious.  Drop me a comment if you would and just say yes/no.  I will also put up a survey at some point if I get industrious.

Conclusion

I know that not everyone who has embraced PowerPivot for Excel has started using PowerPivot for SharePoint yet.  That’s changing, but it takes time.

For those of you who are starting that transition, I’m very excited for you.  I know it sounds weird.  But you cannot appreciate how much more impactful your work “feels” as a web application until you see it in action.  And this post is aimed at helping you reap that benefit.

For those of you who are yet to start down that path, file this one in the back of your mind for later.


Switching Subtotals On & Off Dynamically Using DAX in PowerPivot

January 5, 2012

Guest Post by David Churchward

Cash Flow Statement With and Without Subtotals

Subtotals on or off for a field - They’re the options that you get.  That’s probably great for a lot of situations, but I would put money on the majority of readers of this post having had a situation where they’ve asked “where’s the option to not display a subtotal when there’s only one record being shown?”.  Frustrating isn’t it?  You end up with a load of subtotals simply repeating the same value as it’s own one subset member because one of your other report elements has a subset of data that does need subtotalling.  You can, of course, toggle the show and hide for each member, but wouldn’t it be better if it was dynamic?

Fortunately, DAX has the answer.  It’s not the answer that I would have hoped for because this one feels like it should be an option setting somewhere.  However, we can deliver the same functionality by writing it into our measures.

In this post, I’ll explain how to create a dynamic measure that works out whether a subtotal is needed and displays that subtotal accordingly.  I’ll be using the report that was created as part of the Cash Flow Statement post.

The Subtotal Issue

Let’s refer back to the final report that I created for the Cash Flow Statement.

Cash Flow Statement With Totals2

In the column CF3_Name, the only subtotal that I want to see is the one on Working Capital as this is the only one that has any lower level detail.  You’ll notice that all other areas are carrying subtotals  which only serves to repeat the number above it.

COUNTROWS and COUNTX

In order to solve this problem, you obviously need to know how many subset elements there are that would make up your subtotal.  It would be reasonable to jump straight for COUNTROWS.  Let’s examine that quickly with a measure that we’ll call CF4_Headings_No in the hope that it will tell us how many headings are in our subset.

CF4_Headings_No

= COUNTROWS(VALUES(CF4[CF4]))

COUNTROWS Separate Tables

On the face of it, that doesn’t appear to give us what we want.  We have the same results for all headings and CF4_Name repeats all of the same headings.  The reason that this happens is because CF3_Name and CF4_Name are held on separate tables.  Although they hold relationships to the same table, PowerPivot doesn’t pre-determine which combinations of these fields exist, even at run-time.

So let’s look at what happens when these headings are held on the same table with the same COUNTROWS formula (but obviously changing table name etc!).

COUNTROWS Same Table

That looks better right?  We can see all of the correct combinations of CF3_Name and CF4_Name.  On the one hand, this is good because we can distinguish the fact that Working Capital is the only element that has more than 1 subset item and therefore the only element that requires a subtotal.

However, there’s one big downside here.  For all other sections, we can’t distinguish between a subtotal line and a detail line.  There’s a couple more downsides here too:

  1. I have to create a table that holds all of the combinations of these headings.  This isn’t the biggest issue as I have a table called GL_Headings that holds the codes associated to these headings.  I can create a RELATED()measure in my PowerPivot dataset to return the heading name.  However, why bother if we don’t have to?
  2. Don’t underestimate the power of the function COUNTROWS(VALUES(TABLE[FIELD])) returning a value of 1 which happens when headings are held as a separate table.  This opens up a whole host of functionality and it’s probably one of the most important aspects of PowerPivot in my opinion.

So, what’s the final analysis of COUNTROWS

  1. Using COUNTROWS against a separate table with unique values for each heading gives us the means to distinguish between subtotal sections and detail sections of our report.
  2. Using COUNTROWS against a combined table with heading combinations tells us the CF3 headings that carry detail where we do want to see a subtotal.

I’m sure you’ve probably deduced where I’m going with this as the combination of these two elements probably tells us what we need to know to figure out whether a subtotal is required.  Unfortunately, this is not entirely true.  The problem is that the combination of these elements won’t operate in context unless the context is directly applied against the heading table (ie you put a slicer on the report for the cash flow heading elements).  What about a date slicer?  If you apply a date slicer which is a separate table, these measures won’t react.

Bring on COUNTX

Let’s jump straight into the DAX on this one and see what it’s doing by creating a measure called CF3_Total_Reqd.

CF3_Total_Reqd

=COUNTX(CF4,[Cash_Flow_Statement])

COUNTX is analysing our CF4 table in the context of our measure [Cash_Flow_Statement] (as calculated in the Cash Flow Statement post).  The context applied to [Cash_Flow_Statement] is carried across to our COUNTX formula.  We run this against our CF4 table because we want to get the number of detail heading names that carry a value in our [Cash_Flow_Statement] measure.

So what do we get:

COUNTX

Our CF3_Total_Reqd measure using COUNTX is telling us how many headings are used in our dataset for the MonthEndDate shown on our report.  This is exactly what we want.  What’s even more special is that if, in a particular month, our [Cash_Flow_Statement] measure only has one heading in the Working Capital section, the Working Capital Total would return a value of 1, which is a scenario when we want to switch our subtotal off.

But there’s a problem

Our COUNTX measure, as it stands, is returning a count where we have a heading, but it isn’t telling us when we have a valid blank entry at the CF4_Name level.  As a result, any CF3 category that doesn’t carry CF4 heading detail, isn’t telling us anything.  I know we have Operating Profit elements, but we’re not getting any counts returned.

But what if we specify the column that we’re analysing in our CF4 table?  We can do this by adding in VALUES and specifying the column in our CF4 table.

CF3_Total_Reqd

=COUNTX(VALUES(CF4[CF4_Name]),[Cash_Flow_Statement])

COUNTX With VALUES()

We have a result!  And our Working Capital section is behaving itself too!

And now for the Subtotal Switch On / Off Measure

Consider our two measures:

  1. CF3_Total_Reqd this tells us when a total is required ie CF3_Total_Reqd > 1
  2. CF3_Total_Reqd also tells us where detailed elements exist, ie returns a value of 1, but this measure does the same for those associated subtotals.  CF4_Headings_No, at the same time, helps us distinguish, generally and irrespective of context, between detail and subtotal levels on our report ie CF3_Total_Reqd = 1 AND CF4_Headings_No = 1

If we combine these elements, we get a measure that we’ll call Cash_Flow_Heading_Tidy

Cash_Flow_Heading_Tidy

=IF(

[CF3_Total_Reqd]>1||

([CF3_Total_Reqd]=1&&[CF4_Headings_No]=1),

[Cash_Flow_Statement],

BLANK()

)

Cash Flow Statement Major Subtotals

That gives us what we want, right?  Well not quite.  The Cash Flow From Operations section is now right.  However, the other sections in my CF2_Name column have reached the criteria for their totals to be eliminated.  If I don’t want this effect (and I don’t because this is a major total), I have to specify for my Cash_Flow_Heading_Tidy to directly include those totals.

Cash_Flow_Heading_Tidy

=IF([CF3_Total_Reqd]>1||

([CF3_Total_Reqd]=1&&[CF4_Headings_No]=1)||

COUNTROWS(VALUES(CF3[CF3_Name]))>1,

[Cash_Flow_Statement],

BLANK()

)

Cash Flow Statement Complete

There you have it.  All subtotals behaving properly.


Welcome to 2012: the Year of PowerPivot Everywhere

January 3, 2012

 
PowerPivot

Coming Soon to an… Everywhere Near You Smile

(OK so I said this post was coming on January 2nd, but really I meant the 3rd since today is Tuesday.  Apologies for being so late in the day though). 

Well it’s been a refreshing holiday season.  I actually did a lot less work than I planned.  That’s mostly a good thing, but I committed to a bunch of new things too, so I better have fully-charged batteries rolling into the new year.

So, why do I think 2012 will be the year of PowerPivot?  Well, the first reason is that…  2013 isn’t here yet Smile.  Because I am quite certain that every year will be a bigger year for PowerPivot than the previous.  For a long time.

But 2012 will be the first year where we all start running into PowerPivot in places where we weren’t looking for it.  I certainly see plenty of PowerPivot adoption in places that we all might consider “unlikely,” but I find out about those cases because those people reach out to Pivotstream for assistance.  It’s not like I’m stumbling on it.

But I think that changes in 2012.  I think we will start running into PowerPivot through random personal connections, because its adoption has just reached that point.

I’m increasingly meeting “High Priests” coming downstream while I am paddling upstream.  Lately I keep finding myself on so-called “sales” calls with people who have been using PowerPivot for awhile and glimpsing its potential, and THEY start telling ME why they think PowerPivot is a game-changer.  Not only that, but their reasons, their “talking points” if you will, are as crisp as anything I have ever captured on the blog.  That certainly gets my attention.

Reason #1:  My Uncle-in-Law Savvies the PowerPivot?

A funny thing happened over the holidays.  My wife and I were visiting her family in Chicago, and the usual “so what are you up to these days” type of holiday party chatter ensued.  Her uncle owns his own video editing business, and when he heard the word “PowerPivot,” he said:

         “Hey I edited a video on PowerPivot last year!”

I am not accustomed to this sort of thing yet.  People who aren’t spreadsheet or SharePoint or BI pros really have no reason to know about PowerPivot at this point.  So my response was naturally something like “are you SURE it’s PowerPivot?  Was it computer related?”  Turns out, it was an Intel video from TechEd 2010, which I even attended:

image

Not the best video in terms of content, but the editing is SUPERB

OK, yeah, it’s from a year and a half ago, so it’s not exactly a sign of a recent tipping point. 

But it’s still my first-ever completely random, “normal, non-number-crunching-person has a connection to PowerPivot” moment.  I expect to have many more of these in 2012.

Reason #2:  Blog Stats on the Rise, with an Exponential Flavor

PowerPivotPro.com enjoys a decent page ranking in the search engines, as evidenced by a quick google of the term “PowerPivot.”  As such, I tend to regard traffic here as a decent indicator of overall PowerPivot adoption and awareness.

I’ve guarded these stats closely for a long time now (mostly out of insecurity, and not knowing what counts as “good” traffic for a blog).  But the trend I have been watching is interesting, and I want to provide some detail.

The blog had its first full month in November 2009, about 6 months before PowerPivot v1 was released.  Here is a graph of total page views per month going back to the beginning:

PowerPivotPro Monthly Blog Views Since Inception

PowerPivotPro Monthly Blog Views Since Inception

Notice how the little orange trendline doesn’t actually keep pace with the recent traffic numbers?  That’s because we’ve seen an inflection point this Fall.  A sharp rise.

Curious as to what this would look like just over the last eighteen months, I filtered it down:

PowerPivotPro Monthly Blog Views Since PowerPivot V1 Release Date

PowerPivotPro Monthly Blog Views Since PowerPivot V1 Release Date

That’s probably a better indication of trend, since those 18 months roughly correspond to the time since PowerPivot v1 was released.

Now if we extend the trendline out another six months into the future, we see that we’re trending toward 35,000 a month by June, about 3x what it was the same time in 2010.

Same as Previous Chart But Projected Six Months Into the Future

Same as Previous Chart But Projected Six Months Into the Future

Lastly, it’s instructive to look at the data in “year over year” fashion:

PowerPivotPro Monthly Blog Views Since Inception, Year over Year

PowerPivotPro Monthly Blog Views Since Inception, Year over Year

See how the gain from is bigger from 2010-2011 than it was from 2009-2010?  That’s an example of exponential growth:  the audience is growing at a rate that is proportional to the existing size of said audience.  

One of the hallmarks of exponential growth is that it tends to seem slow at first, because the size of the population is also small at that point.  Later, once it has a good foothold, it surprises you with startling increases in a short period.  This is literally the way that viruses and bacteria multiply, and when something spreads “virally,” it follows this sort of a curve.

For examples of this, see my reference to the “magic eyedropper” story near the end of a previous post, and here’s an article that explains how plants/gardens follow the same sort of growth curve.

Typical Example of Linear vs. Exponential Growth:  Seemingly Slow, then Explodes

Typical Example of Linear vs. Exponential Growth:
Note How the Exponential Curve Seemingly Goes Nowhere for Awhile,
Then Starts to Pick Up, Then Goes Literally “Viral”

Reason #2a:  A Past Observation by Bill Baker

I was at a TDWI conference in San Francisco about seven or eight years ago where I attended a panel discussion.  Bill Baker was one of the three panelists.  Bill was asked if he thought a particular technology (I think it was web services like SOAP) was going to be a big deal or a one-hit wonder.

I really liked his answer, which was to point out that we often tend to OVER-estimate a new technology’s impact when we look ONE year into the future, but we tend to UNDER-estimate its impact FIVE years in the future.  In other words, “hot” technologies tend to “disappoint” at the one year mark, but by the five year mark, they often have quietly popped up everywhere.

Today, it struck me that Bill’s answer is really just the anecdotal way of describing exponential growth:  something that spreads by word of mouth, by example, by experimentation, and by proving itself the hard way, rather than being adopted on command.  I’m pretty sure Microsoft wishes it could command this one, but it won’t have to.

OK, on Thursday we have a killer new post by the esteemed Mr. Churchward.  Stay tuned Smile


On Break for Holidays. Next Post January 2nd!

December 20, 2011

 
image

Back in January with Renewed Vigor and Two Posts Per Week!

Well folks it’s been 15 straight weeks of two posts per week (Tuesday and Thursday), sometimes with bonus posts.  Your PowerPivot bloggers are taking a bit of a break over the next two weeks and then resuming our twice-weekly program with a fresh and rested perspective.

In the meantime we may have a bonus post or two, but no guarantees until January 2nd Smile

Have a great holiday season everyone and we’ll see you in two weeks.


Cash Flow Statement in PowerPivot

December 15, 2011

 

Guest Post by David Churchward

Cash Flow Statement

There’s few, if any, reports that I consider to be more important than the Cash Flow Statement.  Every business needs one, probably above any other report.  There’s numerous different versions of Cash Flow reports and, in reality, it can become a very personal thing to a company so I’m not going to propose to provide a one size fits all report.  In addition, I’m not going to proclaim to provide an IAS7 – Cash Flow Statement (that’s International Accounting Standards) textbook report because this isn’t designed as an accountancy lesson (but, if you’re interested, the method I’ll show here relates to the Indirect Method in IAS7).

With that said, if you consider this post alongside Kasper’s excellent post Building a cash flow statement in PowerPivot using Dynamic Measures in DAX, you should have all the tools you need to produce any Cash Flow Statement that you require.

The Accountancy Bit (very quickly!)

Just before we start, a quick accountancy point to consider.  Kasper’s approach considers cash payment and receipt transactions.  My model uses all transactions in the general ledger with the exception of Bank transactions.  On the basis that double entry exists (ie every transaction has an equal and opposite effect), all transactions that aren’t the bank transactions must equate to the same value.  The reason we use the “other” side of the account is because this side of the transaction tells us what the cash transaction was for.  As a result, we should simply be able to aggregate transactions into Cash Flow categories.

This seems quite straight forward.  Unfortunately, there are a few exceptions that need to be handled.  I’m only going to explain one which should give you the means to adjust for others.

Depreciation is purely an accounting adjustment.  This has the effect of crediting the balance sheet and debiting the P&L.  The effect of crediting the balance sheet has the effect of reducing the value that will be shown as Fixed Asset additions.  We therefore net off the depreciation transaction as if it never happened and I’ll show this later in this post.

The Dataset

My dataset (FACT table) contains 3 columns:

  1. GL_Account– this is my general ledger code.  Every transaction that forms the trial balance will carry a general ledger code and this tells us what the transaction was for.
  2. Month_End_Date – this date tells us the financial period to which the transaction relates.  I would advise using the month end date of the financial period in which the transaction will be reported as I’m doing in this example. (or a period number as in Rob’s Greatest Formula In The World posts).  It should be noted that a transaction date may not be in the same calendar period as the reporting date so care should be taken.
  3. Amount– this is the transaction value.  Using normal accounting signage, this will be a positive value for debits and a negative value for credits.

My dataset contains all transactions processed on the system – this is PowerPivot, it can handle it – and this essentially forms the basis of the trial balance.  If you have a lot of old data and don’t want to include it all, you could substitute historic data with opening balance values for each general ledger code.  This simply aggregates a lot of old transactions into one balance (per general ledger code) for an opening balance date, whilst maintaining the overall integrity of a balanced trial balance and the associated values.

You may have a dataset that holds monthly values for each general ledger code as opposed to each individual transaction.  This will work equally well although you won’t have the means to dissect the Cash Flow Statement by subset records such as customer or project.

If your data is held as monthly columns, it’s worth running an UNPIVOT.  Whilst we could condition PowerPivot to work with individual values for each period, it’s more efficient to work with one value column with associated period dates held in another column.

Related Tables

I link my my FACT table to a GL_ACCOUNTS table on the GL_Account code.  The GL_Accounts table provides details relating to the GL_Code such as account name and  report heading codes.  These heading codes, in turn, link through to a further GL_Headings table which holds cash flow report heading codes.  This, in turn, links through to cash flow heading tables.  It’s these headings that we will use on our Cash Flow Statement report.

Cash Flow Statement Dataset Schema

image

You’ll notice that CF1 doesn’t link to any other tables.  I’ll come onto that shortly.

General Ledger Account Mappings

The GL_Headings mapping is the critical element to this dataset.  This provides all of the key relationships between a general ledger code and the Cash Flow Statement report heading that you want the account to be represented under.

GL_Headings Table

image

My GL_Accounts map through to my Heading_Code on this GL_Headings table.  This table holds all of my key report headings and provides a useful grouping of accounts.  For instance, all general ledger codes that relate to Sales will carry a Heading_Code of 1010.

These definitions are important.  This is a one-off setup and you’ve probably done this indirectly in some way or another to drive any reports or Excel analysis that you’re currently doing (probably with VLOOKUP).  This process simply affirms that mapping.  Ideally, you would code these heading codes into your General Ledger account code setup and formulate the code allocation as part of the process to set up new general ledger accounts.

You’ll recall that I mentioned Depreciation earlier in this post.  Whilst this is a P&L account (heading code 1045 in this example), I’m coding this to exactly the same place as Fixed Assets on the Balance Sheet (heading code 2010).  This effectively eliminates the deprecation transactions.  An alternative would be to filter out the accounts in question.  You can do this, but be careful to ensure that those accounts net to zero.

Each of these codes map through to Cash Flow Statement heading tables.  These heading tables can be whatever you need them to be, with headings and ordering assigned however you want your final report to be represented.  The one’s I’m using are shown below.

CF2 – Cash Flow Statement Heading 2

image

This is my first grouping of headings.  These align with the IAS7 headings for CF2 codes 1, 2 and 3 and basically split my Cash Flow Statement between Operations Activities, Investing Activities and Financing Activities.

There’s a fourth section called Bank.  The Bank general ledger codes map through to this code and we eliminate them for the Cash Flow element of this report.  However, we bring them back into action when we display the Bank Balances at the end of the report.

CF3 – Cash Flow Statement Heading 3

image

This is the next level of granularity on my report.  The Bank general ledger codes don’t have any CF3 mapping and yet I’m carrying Opening and Closing Bank Balance codes on this heading set.  I’ll come onto why that is a bit later.  You’ll also notice that I’ve coded these headings with an Open_Bank  and Close_Bank flag.  We’ll use dynamic DAX measures later on to utilise these.

Note – there should NOT be any mapping of accounts to the CF3 codes 10 and 11 in this table (ie Open and Close Bank Balance).  We’ll use these simply to drive a DAX measure later.

CF4 – Cash Flow Statement Heading 4

image

One element of my Cash Flow Statement will carry a further breakdown – Working Capital (although you can have more if you want).  I’ve done this simply to provide an extra level of granularity, but you could decide to replace the Working Capital heading in CF3 with these headings and map accordingly.

I’ve got a few reasons for doing this:

  1. I like to show my Working Capital elements specifically – this targets the key operational balance sheet items that generally need to be tracked
  2. This helps to line up a future post!

CF1 – Cash Flow Statement Heading 1

You might, quite rightly, question why my ordering has gone to pot and I’m explaining CF1 last!  Quite simply, this table sits out on it’s own because it simply drives report sections as opposed to being a mapped heading code.  I’m going to show a Cash Flow section and then, below that, I’m going to show the effect on the bank balance.  No relationships required.

image

And Now for the DAX – Cash Flow

I’ve got to be honest, this measure isn’t going to set the world alight.  However, this goes to show how easy PowerPivot can be, especially if you condition your data properly.  I’m creating a measure aptly called Cash_Flow

Cash_Flow

=CALCULATE(

SUM(FACT[Amount]),

CF2[CF2_Name]<>”BANK”

       )*-1

This is a simple CALCULATE function which sums the [Amount] field on the FACT table with a simple filter set to ignore any GL_Accounts that have a CF2 category mapping of “BANK”.

You’ll notice that I multiply this by –1 to reverse the signage.  In simple terms this is because of the double entry effect.  We’re using the “other” side of the transaction which means that the sign convention is going to be back to front.  This simply reverses that effect.

When I pull this measure onto my report together with the CF1,2,3,4 heading names, I get the following.

Cash Flow in Excel - PowerPivot Turns Complex into Simple

You might say that this is job done (especially if you remove CF1 heading from the report). This does give us a Cash Flow Statement. However, this doesn’t give my bank balances and, if I include my CF1 heading, my report is repeating the same data for both of the CF1_Name headings. This is understandable as CF1 is not linked to my FACT table in anyway.  This is intentional (believe it or not!).

Bank Balances

I want to show opening and closing bank balances for the Bank section of my report and this is where it gets a bit more interesting.  Let’s create a measure that calculates these balances and let’s call this measure Bank…

Bank

=IF(COUNTROWS(VALUES(CF3[CF3]))=1,

IF(VALUES(CF3[Close_Bank])=1,

CALCULATE(

SUM(FACT[Amount]),

ALL(CF3),

CF2[CF2_Name]=”BANK”,

FILTER(

ALL(Month_End_Dates[MonthEndDate]),

Month_End_Dates[MonthEndDate]<=

MAX(Month_End_Dates[MonthEndDate])

            )

          ),

IF(VALUES(CF3[Open_Bank])=1,

CALCULATE(

SUM(FACT[Amount]),

ALL(CF3),

CF2[CF2_Name]=”BANK”,

FILTER(

ALL(Month_End_Dates[MonthEndDate]),

Month_End_Dates[MonthEndDate]<=

EOMONTH(MAX(Month_End_Dates[MonthEndDate]),-1)

  )

),

BLANK()

   )

    )

      )

We should be offering prizes for those of you would can instantly spot the GFITW elements!!  Anyone would think that this had somehow been contrived!  Believe me – it hasn’t.  This is a concept that I use regularly and it’s a joy to see Rob explain it so well so I don’t have to!

So what is this doing?  I’ll explain as clearly as I can, but it’s worth paying very close attention to Rob’s Greatest Formula In The World posts.  I won’t re-iterate too much here.

  1. The first IF statement simply serves to provide an answer as to where I want the measure to be evaluated.  I want an answer when my CF3_Heading is flagged as Open_Bank or Close_Bank.
  2. The second IF statement creates a value when my CF3_Heading [Close_Bank] is flagged.  Where this is the case, the following happens:
    1. Sum the [Amount] Field
    2. Expand my dataset to all CF3 headings in order to release the dependency on the current CF3 heading being evaluated – ALL(CF3)
    3. Apply a filter to include all of my Bank general ledger codes – CF2[CF3_Name]=”BANK”
    4. Apply a further filter (FILTER) that:
      1. Removes the dependency on the MonthEndDate – ALL(Month_End_Dates[MonthEndDate])
      2. Apply a filter that includes all months that pre-date and include the reporting month – Month_End_Dates[MonthEndDate]<=MAX(Month_End_Dates[MonthEndDate]) – this is important because the transaction base for the month won’t give us the balance.  We need to include ALL transactions that pre-date and include the reporting date.
  3. The third IF statement has a similar effect to the second IF statement, but it produces an opening balance and therefore the current reporting month has to be ignored.  As a result, I want to sum all transactions where the date is less than or equal to my prior month date – Month_End_Dates[MonthEndDate]<=EOMONTH(MAX(Month_End_Dates[MonthEndDate]) ,-1)

Cash Flow in Excel with Bank Balances Thanks to PowerPivot

Once again, we have the correct results but we’re getting values repeated for both CF1 headings.

Sorting Those CF1 Headings

We now have our two base measures.  All we now need to do is evaluate when to use each one.  Let’s create another measure called Cash_Flow_Statement.

Cash_Flow_Statement

=IF(COUNTROWS(VALUES(CF1[CF1]))=1,

IF(VALUES(CF1[CF1])=1,

[Cash_Flow],

[Bank]

   )

)

This measure simply evaluates for CF1 headings and determines that if my CF1 Heading Code is 1 (ie Cash Flow) then use my [Cash_Flow] measure.  Otherwise, use my [BANK] measure.

Cash Flow Finished

A bit of formatting and there you have it.  You’re just about done.  Or rather, you’re done if you think that’s enough.  I, however, don’t like some of these totals and duplication of values in certain areas.  There’s a way to deal with those totals but that’s a topic for a future post.

So what else can we do with this?

Just as a taster, here’s something that I like to call a Cash Flow Bridge.  This could be a topic for a future post, but just to whet your appetite……

Cash Flow Statement Bridge

If there’s enough call for this, I’ll get this scheduled in for a future post.  Neat eh!


The Greatest Formula in the World, Part 3

December 13, 2011

 
Our time machine that we developed in part one and part two still needs some explanation, so let’s dive in.

First Things First:  The MAXX Wasn’t Needed

Looking back, I noticed that I was overcomplicating things needlessly.  The final formula I had involved the following FILTER() term, in which I used a MAXX:

FILTER(ALL(Periods),
       Periods[NextYear Period]<=
          MAXX(VALUES(Sales[Period Num]), Sales[Period Num])
)

Turns out that MAX() works just fine, so let’s replace that clause and simplify things a bit.  Here’s the new formula:

CALCULATE([Total Sales],
   ALL(Periods),
   FILTER(ALL(Periods),
      Periods[Year]=MAX(Periods[Year])-1
   ),
   FILTER(ALL(Periods),
          Periods[NextYear Period]<=MAX(Sales[Period Num])
   ),       
   VALUES(Periods[MerchPeriod])
)

OK, with that, we can move on to explanation:  How does this formula work??

I used to call this technique “expand then filter”

Well actually I still do, in my own head.  It’s just that the GFITW is a catchier title.

OK, so the “expand” part is just that first ALL():

CALCULATE([Total Sales],
          ALL(Periods),

The first step in the formula, then, is basically just telling the calc engine to throw away all filters on the Periods table.  In other words, “forget all concept of time, pretend the pivot is not filtered at all with respect to time.”

We do this so that we have a clean slate.  Then, in the subsequent FILTER clauses, we build up a new filter context for time.

One more time for clarity:  the way this formula works is to first throw out all time filters, and then in subsequent steps, we build up new filters to match the time period that we want, which in this case is last year.

Once you understand that, this overall formula starts to get pretty simple.  Each piece of the formula is quite straightforward in its own right.  ALL() is pretty straightforward for sure, and so are the subsequent FILTERS().

OK, we’ve expanded.  Now on to the filters!

The first filter says, “hey, now that we’ve thrown out all time filters, let’s filter time back down to just be last year.”

FILTER(ALL(Periods),
       Periods[Year]=MAX(Periods[Year])-1
)

Let’s talk about the FILTER() function itself for a moment.

How does FILTER() Work?

Honestly this function has deserved its own post for a long time.  I’ll give a brief explanation here.

The syntax for the FILTER function is FILTER(TableToFilter, FilterExpression).   Pretty simple.  Here’s some more detail:

  1. FILTER() takes a TableToFilter and a FilterExpression, and returns all rows from that TableToFilter that match the FilterExpression.
    1. In the example above, TableToFilter is ALL(Periods)
    2. and FilterExpression is Periods[Year]=MAX(Periods[Year])-1
  2. FILTER() steps through the TableToFilter one row at a time. 
    1. And for each row, it evaluates the FilterExpression.  If the expression evaluates to true, the row is “kept.”  If not, it is filtered out.
    2. Because FILTER() goes one row at a time, it can be quite slow if you use it against a large table.  When I say “large” that is of course subjective.  A few thousand rows is fine in my experience.  A million is not.  Do not use FILTER() against your fact table.
  3. The FilterExpression typically takes the form of Table[Column] = <expression>
    1. The comparison operator doesn’t have to be “=”.  It can also be <, >, <=, >=, <>
    2. The expression on the right hand side of FilterExpression can be “rich.”  This is VERY useful.  In a simple CALCULATE, the right side of each filter expression has to be simple, like a literal number (9) or a string (“Standard”).  The fact that FILTER() allows for rich expressions here is one of the most common reasons I use FILTER().
    3. The Table[Column] in the filter expression is a column in the TableToFilter.  If you are filtering the Periods table, it makes sense that you are testing some property of each row in Periods.  I can’t think of a sensible reason to use a column here that is NOT from TableToFilter.  (Insert “boot signal” here, maybe the Italians can address this).
  4. FILTER() ignores everything else going on in your formula and acts completely on its own.
    1. For example, our overall formula sets ALL(Periods) as the first argument to CALCULATE.
    2. The FILTER()’s that come after that do NOT pay any attention to other arguments however, including that ALL(Periods).
    3. In other words, the FILTER() functions are still operating against the original filter context from the pivot!  If the pivot is sliced to Year=2009, then the FILTER() function starts with the Periods table already pre-filtered to just 2009.
    4. This is why each of my FILTER()’s uses ALL(Periods) for TableToFilter.  I have to repeat the “expand” step so that my FILTER() is also working from a clean slate.
  5. Even though each FILTER() operates on its own, their results then “stack up” in the overall formula.
    1. Even though FILTER() RETURNS a set of rows that matched the FilterExpression, it actually REMOVES rows from the overall filter context.
    2. This sounds tricky but really it isn’t.
    3. Let’s say our TableToFilter contains 6 rows:  A, B, C, D, E, and F.
    4. And our overall formula contains two FILTER() clauses that both operate on the same TableToFilter, just like our overall formula near the beginning of this post.
    5. Let’s also say that the first FILTER() returns rows A, B, C, and D.
    6. And the second FILTER() returns rows C, D, E, and F.
    7. The net result is that only rows C and D are left “alive” in the overall filter context of the formula.
    8. So one way to think of this is that FILTER()s “stack up” on top of each other.
    9. Another way to think of it is that even though the first filter RETURNED rows A, B, C, and D, its real effect was to REMOVE all other rows (E and F) from consideration.

OK, back to that first filter!

Here it is again:

FILTER(ALL(Periods),
       Periods[Year]=MAX(Periods[Year])-1
)

Let’s revisit points 1-5 above for this FILTER expression to see how it all works.  And let’s examine just a single cell of the pivot to see how this FILTER operates for that one cell:

image

Focusing on The Orange-Circled LASTYRSALES Cell As An Example
With Its Period Filter Context Highlighted in Green

In that picture above, the orange cell we are looking at has a filter context “coming in” from the pivot.  It has Period[Year] set to 2011 and Period[MerchPeriod] set to 1, as highlighted in green.

Given the detailed description of FILTER() from points 1-5 above, we can see that:

  1. We set ALL(Periods) as our TableToFilter so that we are starting from a clean slate with respect to time.  So our Periods table now has “all rows alive.”
  2. Then our FilterExpression tests against the Periods[Year] column.
  3. MAX(Periods[Year]) – 1 still operates independently!, so it still picks up Periods[Year]=2011 from the pivot.  Therefore it returns 2011 – 1 = 2010!
  4. Since we started with ALL(Periods) as the TableToFilter, and the FilterExpression only “keeps” rows where Year=2010, we are left with all 2010 rows “alive” after evaluating this FILTER().
  5. If we didn’t do ALL(Periods) for TableToFilter, and instead just used Periods without the ALL(), our FILTER would start out with only rows from 2011 (since that is what the pivot is telling us).
    1. And then in the next step when we go back a year to 2010, FILTER() would find no rows.  There are no rows that match Periods[Year] = 2010 and Periods[Year]=2011. 
    2. So our FILTER would return no rows, which means it would have the effect of REMOVING all rows from Periods in the overall formula, and our measure would return blank for all cells in the pivot.

That’s a lot of explanation, I know.  Walk through it a few times.  It’s actually pretty intuitive once you’ve done it a few times.  The tricky part, for me, was discovering all of these details for myself.  And since I’ve done all of that, you don’t have to.

That’s enough for this time.  I think you can probably figure out how the second FILTER() evaluates based on the above, but I will step through it next time. 

I will also explain why we use that last VALUES() in the formula, and probably also share some of the answers I got from the Italians, and from David Churchward, in response to my question “did I need to add that calc column in the Periods table?”


Friday Bonus: Gang Sign Photos So Far

December 8, 2011

 

This is my favorite so far, by the narrowest of margins.  It comes from Angel Abundez of RDP Streamline Solutions.  And Angel (twitter) executes quite well.  Note the form.  Good X – not the V or the Y that most people’s X’s are turning out to be.  And a sharp L.  The background pic is nice too.

But his daughter simply nails it.  Look at that total lack of emotion.  A stone cold spreadsheet killa.  Everyone should aspire to her standard of excellence.

VIEW THE FULL GALLERY HERE

I’m gonna leave submission open for a few more days.  Plenty of time to get yours in!

SUBMIT YOUR PICTURE(S) HERE


The Greatest Formula in the World, Part Two

December 7, 2011

image

Our Time Machine From Part 1 Needs a Couple of Fixes

OK, if you recall from part one, we had a “year over year” time machine calculation going on, and it was built against a data set that lacked a “real” calendar table.  Very cool.  Very resourceful.  And very necessary.

But the time machine had two problems.  Let’s fix them.

Problem #1:  Meaningless Grand Total

Let’s start with the easy one:

Year over year in PowerPivot - Meaningless Grand Total

Grand Total is Meaningless for Last Year Sales

It is meaningless to have a “grand total” value for a measure that returns “last year’s sales.”  What year would that BE, actually?  It’s nonsense.  So we use an old trick, one of the many flavors of IF(VALUES()):

=IF(COUNTROWS(VALUES(Periods[Year]))>1,BLANK(),
   CALCULATE([Total Sales],
      ALL(Periods),
      FILTER(ALL(Periods), Periods[Year]=MAX(Periods[Year])-1),
      VALUES(Periods[MerchPeriod])
   )
)

Where the new IF “wrapper” is highlighted and the original formula is in normal font.

For more on that “IF VALUES” technique, please see this post.

The results are as desired, the grand total is now blank:

image

Problem solved.  Moving on…

Problem #2:  2011 isn’t complete but we’re getting all of 2010 sales

Remember, our sales data for 2011 only goes through the first 6 months.  So we do NOT want “last year sales” for months 7-12:

image

That can be solved a number of ways.  The simplest is just to add another IF(), and have the Last Year Sales measure return BLANK() whenever there are no Sales:

=IF(COUNTROWS(VALUES(Periods[Year]))>1,BLANK(),
   IF([Total Sales] = BLANK(), BLANK(),
      CALCULATE([Total Sales],
         ALL(Periods),
         FILTER(ALL(Periods),
            Periods[Year]=MAX(Periods[Year])-1
         ),
         VALUES(Periods[MerchPeriod])
      )
  )
)

That trims the results to just the months desired:

image

But note that the subtotal for 2011 is still too high:

image

“Last Year Sales” for 2011 Should Only be Returning
2010 Sales Through the First Six Months

This one is trickier.  I struggled to find a good answer before coming up with the following:

Step 1:  Add a “Next Year Period Num” Column to the Periods Table

Recall that my Sales table has a “Period Num” column that is the basis for the relationship with the Periods table:

image

And that matches up with a similar column in the Periods table:

image

Note that Period Num does NOT reset to 1 with each new year (unlike MerchPeriod).  So that is the absolute unique ID for a given Month/Year combo.

Well, I created a new column in the Periods table that tells me, for a given Period Num, what the equivalent Period Num will be NEXT year:

image

Now, in my FILTER statements, I can choose to match on THAT column instead.

Bringing it Home

OK, now that I have that column, I can add a new FILTER clause to my measure:

=IF(COUNTROWS(VALUES(Periods[Year]))>1,BLANK(),
   CALCULATE([Total Sales],
      ALL(Periods),
      FILTER(ALL(Periods),
         Periods[Year]=MAX(Periods[Year])-1
      ),
      FILTER(ALL(Periods),
         Periods[NextYear Period]<=
            MAXX(
                VALUES(PeriodSales[Period Num]),
                PeriodSales[Period Num]
                )
      ),
       
      VALUES(Periods[MerchPeriod])
   )
)

OK, what does that do?  Simply put, it further filters the Periods table to NOT go beyond any periods for which we currently have records in the Sales table.

And the results:

Last Year Sales Measure in PowerPivot With a Custom Calendar

Last Year Sales Measure Doing the Right Thing

And now if you want YOY Growth, it’s straightforward:

=([Total Sales] – [LY Sales Finished]) / [Total Sales]

Which yields:

Year over Year / Year on Year Growth Percentage Measure in PowerPivot With a Custom Calendar

Year over Year / Year on Year Growth Percentage
Measure in PowerPivot With a Custom Calendar

OK, I cheated and wrapped another IF(COUNTROWS(VALUES)) around the outside of the formula so that the grand total cell is blank again, because again, that’s a meaningless value to report.  Details.

Isn’t that a lot of work?

Depends on how you look at it.  First of all, it’s a lot harder to grasp the first time than it is as you get used to it, trust me.

But even better, this investment pays off forever.  Normal Excel formulas may be easier to write the first time, but then you have to re-write and adjust them forever, every time your data changes.  And every time your desired report shape changes.

This one is a portable formula.  It goes wherever you want it to go, and eats whatever data you feed it.  Forever.  It’s worth a little extra effort.

OK but do I really have to understand all of that?

No, not really.  Not right away.  Think of it this way:  this is what I do all day, every day.  And I can tell you that figuring this out is not something you want to do in your spare time.

But once someone gives you the pattern?  Wash, rinse, repeat.  Make small adjustments as needed.

Honestly, that whole formula above could be wrapped up in a function provided by Microsoft, and all of the nasty stuff hidden.  I told them as much last time I visited Redmond.  And if it were a function rather than a formula, we wouldn’t care at all how it worked.

So… treat this as a pattern.  Copy/paste and modify to fit your needs.  Seriously.

Unfinished Business

I actually WILL retrace my steps here though and explain a number of things though, so that you CAN understand.  I have a couple of posts in the queue aimed at just that.

Were there alternate ways to write this measure?

Yes, there were, especially in that last step where I needed to get the “Last year sales” measure correct for the 2011 subtotal.  I could have used SUMX to make the year subtotal equal to the sum of its underlying months.  That is worthy of a post for sure.

But I was wondering if there was still another way.  A way that doesn’t use SUMX and doesn’t require a new calc column.

And for that, we need the Italians.  So I’m gonna try out my new toy, the Boot Signal:

image

Calling Marco and Alberto

Get it?  *Boot* Signal?


The Greatest Formula in the World, Part One

December 6, 2011

 
image

Play Write the greatest song formula in the world, or I’ll eat your souls.”
-From “Tribute,” by Tenacious DAX

A Do-It-Yourself Time Machine

You remember the Great Precedence Project?  Well, I have shelved it for now, for two reasons:

  1. Creating an exhaustive list of all the precedence rules in PowerPivot formulas was going to be…  exhausting.
  2. I didn’t really need to boil the philosophical ocean in search of deep underlying meaning, because on further inspection, I already had the Greatest Formula in the World, and needed no other.

So what is the GFITW about?  It’s about time navigation.  It’s useful when you have a custom calendar and the time intelligence functions are therefore not so helpful.

The GFITW is a do-it-yourself time machine.

Year on Year Sales With a Custom Calendar?  Yes We Can!

In that post linked above, which happened to be the last installment of the precedence project, I was calculating a running total, and doing so without benefit of the fancier functions like DATESYTD etc. (which rely on the “real” calendar, not your business calendar).

OK, so now let’s do a “Year on Year” sales measure, sometimes called a “Year over Year” measure.  And again, our “calendar” table isn’t a true calendar at all:

Semantically this IS a calendar but functions like PREVIOUSYEAR can't use it

A Table of Periods (Not Dates) Means You Cannot Use the Built-In
Time Intelligence Functions to Calculate Year-on-Year Sales

And the Sales table is very simple:

Sales Table linked to a period number, not linked to a date

Sales Table is Linked to the Periods Table by the Period Num Column

And I have this basic pivot already set up:

image

Year and MerchPeriod on Rows

So, how do I write a measure that “fetches” the sales from last year?

Let’s Skip Some Steps

I am going to be honest with you:  it took me a very long time to figure this out.  The formula looks reasonably simple, and it is, but I had to try a million variations before I got it right.  Literally, it took me about a week to refine it.

So rather than walk you through that painful process, let’s skip ahead and show you the GFITW in all its glory.  Then in the next post I can show you what NOT to do, and we can also fine tune it.  OK?  OK.

So here it is, the Greatest Formula.  In the World:

=CALCULATE([Total Sales],
   ALL(Periods),
   FILTER(ALL(Periods),
      Periods[Year]=MAX(Periods[Year])-1),
   VALUES(Periods[MerchPeriod])
)

And its results:

image

No, it’s not perfect yet.  We will need to calculate percentage growth of course, rather than merely fetching last year’s sales.  And that given that 2011 is not yet complete, I’m a little squeamish about Last Year Sales returning ALL of 2010’s sales (the $5.9M number).

But for now, let’s count our blessings.  This formula DOES fetch the sales from last year, and it works (mostly) both at the year level and the MerchPeriod (aka Month) level.

Dissecting the Formula

Here is the formula again:

=CALCULATE([Total Sales],
   ALL(Periods),
   FILTER(ALL(Periods),
      Periods[Year]=MAX(Periods[Year])-1),
   VALUES(Periods[MerchPeriod])
)

But really, the GFITW is not a formula.  It is a pattern that you can re-use and modify.  So let’s look at it that way:

=CALCULATE(Original Measure,

   ALL(Your Custom Calendar Table),
  
   FILTER(ALL(Your Custom Calendar Table),
      Year Column Or Similar =
        
Expression that “moves” the Year Column
  
),
  
   VALUES(
Time Column That is More Granular
          Than Year, Like Month or MerchPeriod

  
)

)

Where everything in blue is “fixed” as part of the pattern, and everything in italics is something you can change.

Like I said, this is running a bit long for one post.  Come back Thursday for the rest Smile