Learning DAX Measures – the “Spicy Function” Scale

November 16, 2010

 
DAX Function Spicy Complexity Rating Scale

“I will start with the calculate curry.  And a green tea.”

-Wise first time DAX customer

Is There a Preferred Way To Learn DAX Measures?

I’m glad you asked :)   Actually, I do get asked this quite often – in email, on Twitter, and in person at events like last week’s PASS Summit in Seattle.  I promised the folks at my Birds of a Feather lunch table that I would blog about the approach that I take in my consulting/training engagements.

I then, of course, promptly forgot.  Good thing Phil reminded me today in Twitter, because it gave me an opportunity to put together that menu mockup above.  Which clearly is where my time is best spent while watching Monday Night Football.

So, here it is.  The official PowerPivotPro technique, refined by decades spent in the trenches of DAX.  But first, some background.

Sometimes, You Actually CAN Have Too Much of a Good Thing

If you read my post on the official Excel blog, you may remember me saying something to the effect that DAX measures are a feature so rich, it’s as if Excel had a whole team working on them for a decade, then delivered it all at once in a single release.

That’s obviously a good thing, but it also comes with a downside:  it’s a lot to digest all at once.  Most products give you the simple stuff in v1, then add some more power in v2, continue in v3, etc. – and the user base gets to grow their knowledge slowly over time.

Not so in PowerPivot v1.  We’re basically looking at a version 5 product when it comes to DAX measures and all of the functions supported.  So it’s a bit daunting – of all these many functions, which ones would have been released in v1, had we not skipped straight to v5? 

Because, hey, those are the ones we want to learn first.  But, they are hiding in there next to functions from v2 – v5, and the function names provide little clue as to complexity.

The Spicy Scale to the Rescue!

On Thursday night we had a very entertaining dinner with members of the PowerPivot/SSAS team.  At my table, we discussed the idea of a spiciness scale for DAX functions, to help people approach them in the right order.  It would be just like the spicy scale you see on menus at Chinese and Thai restaurants.

(I was suggesting the idea as something that might be useful in the product itself – I now have the luxury of just throwing out ideas at random, and my former colleagues decide whether it actually makes sense in the real world…  in a sea of ideas coming from all directions.  Their job is a LOT harder.)

Table 2
                      

Some amazing people in those pictures, including, but not limited to, people who get mentioned here all the time – Kasper (now on the PowerPivot team), Marco and Alberto, Marius of DAX Superhero fame…  and that is leaving out some of my all-time favorite people.

OK, let’s dive in.

Spice Level One:  Fundamentals, COUNTROWS, and DISTINCT

Before you get rolling, it is very important to understand how measures actually work.  And while you’re at it, it helps to have a couple of new (but simple) functions to try out.

This explanation works best in video form, so I’ll direct you to my YouTube video on the topic.

Spice Level Two:  CALCULATE

Now that you understand the basics of pivot cell context and how those filters apply to measures, it’s time to start overriding and modifying that filter context.

CALCULATE is the foundation for a whole world of magic, and it’s a lot like SUMIF, which is excellent news for Excel pros.

You can learn more about CALCULATE here, here, and here.

Also note that you don’t have to restrict yourself to the = operator here.  You can use <, >, <=, >=, and <> as well.

Spice Level Three:  ALL

Once you get comfortable setting fields to single values, the next expansion of your powers is removing filters altogether.

ALL is what you need.

Spice Level Four and Beyond:  “It Depends”

As I’ve mentioned before, the best way to learn is with your own data, rather than textbook cases.  So I would let that be your guide.

Many people will probably want to experiment with time intelligence functions next, employing them to change date filter context in much the same way that ALL does…  except with more specific, time-shifting results.  I really should do a new series of posts just on time intelligence functions.

Or alternatively, do you want a measure that iterates over values that are NOT shown in your pivot?  Or do you want a measure to be a MAX at the lowest level of the pivot but then a SUM at higher levels?  If so, I recommend you try SUMX next.

Or maybe you want to revisit CALCULATE, and instead of setting fields to particular values, or even comparing then to particular values using <, >, <=, >=, or <>, let’s say you want to compare those fields to *measure* values?  Well, you are ready for FILTER.  Sort of :)

I will probably return to this subject in the future, time allowing, but for now, this is the gist of it.  If you master levels 1-3, you have a tremendous amount of new power at your fingertips, and you are ready for new things, but it’s hard to cover any of those new things in a short paragraph or even a single link.  I usually spend several hours on the level four stuff with my consulting/training clients, as a point of reference (and that is with the comfort of the clients’ own data and business problems).


Six Months With PowerPivot, part one

April 23, 2010

simply_red1

   
“If you don’t know me by now…  you will never never never know me…”

In honor of PowerPivot v1’s public release, I thought I’d offer up my thoughts on my last six months working with the product. 

Remember, I physically left Redmond in August and then officially left Microsoft in February, but have been putting PowerPivot through its paces that whole time, with a wide variety of data sets and business scenarios.

So in some sense, you can’t really get a closer view of PowerPivot than I have, while still maintaining any sense of neutrality about the product.  So here it is, the honest truth…

It passed the Great Football Project Challenge

When I started the Great Football Project back in October, I really did not know what to expect.  Honestly, I wasn’t sure that it was a great idea – was I going to get 5 days in and discover that PowerPivot simply wasn’t suited to that problem?  There was genuine potential for embarrassment.  But I needed something to blog about, and I was anxious to get started, so I just dove in.

After a few weeks, I was still holding my breath a bit.  I was past the basics but hadn’t really pushed the envelope at all.

At some point though I just stopped wondering.  It wasn’t until recently that I looked back and realized that I was building features, like the Rank measure, that were never in the original project at all. 

I can say now with confidence that PowerPivot can absolutely handle the business logic phase of the football project, which the consultant back in 2006 described as one of the most complex cubes he’d ever seen.

I call that a success.  Note how I specified the “business logic phase?”  That brings me to the next topic…

It is NOT a data cleaner/shaper

OK, this is perhaps obvious since the PowerPivot tables cannot be edited, and there are no features/functions that let you reshape rows.  Yes, you can add calc columns and that often does the trick, but there are other cases (like for instance, removing dupe rows) that PowerPivot can’t do at all.

The whole “shape it in normal Excel and then paste it over to PowerPivot window” workaround is ok for one-off work, or for tables that you don’t expect to change very often.  But like many of you, I am striving to gain the benefits of automatic nightly data refresh that the server provides, and the Excel workaround doesn’t translate to that system at all.

So, even more than ever, you need a clean and properly-shaped data source to start with.  So the first half of the work that the consultant did for the football project in 2006, where the text files were imported into SQL and turned into a decent schema, is still very much required.

For a production system, I don’t think this is a bad thing at all.  It forces you to cooperate with IT (or whoever owns your databases) to give you what you need.  And it forces them to listen to you more clearly, as long as they care about “taming the Excel beast” that is always their favorite thing to complain about :)

For a production system, that cooperation is essential for robust results.  And if it’s not a production system, then yeah, the Excel shaping workaround is great.

“No, it can’t do that.  Oh, wait. Nevermind.  Yeah, it CAN do that.”

Having worked on the product from the beginning, I’m more closely familiar with its limitations than most people.  In some ways that’s an advantage of course – I don’t dive into projects only to find out later that it can’t be done.

Oddly though, so far, knowing the limitations has largely just been a hindrance.  Every time my initial answer was “no, not in PowerPivot v1,” I’ve turned out to be wrong.

I have succeeded using PowerPivot to solve every single real-life problem I’ve encountered in my first six months of using it.

Market basket analysis?  Ranking measures?  Standard deviation?  Many to many relationship problems?  Godawful horrible data sources?  Measures that calc according to different formulas at different levels of the pivot?  Iterating over variables that aren’t even in the view?  PowerPivot has defeated them all.  Well, more accurately, I have defeated them all with PowerPivot.  It’s not like I sit back and watch PowerPivot do its thing.  It is not always easy.  Which brings me to the next point:

Challenging and Rewarding

You know those rare occasions where you suddenly find yourself in the fast lane?  When your brain is forced to expand?  When you are truly challenged, in a good way?

I’m talking about a specific kind of challenge, the good kind.  Not the kind like when you take a new job and are overwhelmed by all the new rules and bureaucracy you have to learn.  And not even the kind when you’re learning most new technologies (HTML and XML come to mind).

The best examples of this “positive challenge” vibe from my life are the ones where I’ve been pushed by a mentor.  A couple of teachers come to mind.  Some specific coworkers as well – Zeke Koch, David Gainer, and Amir Netz most prominently.  Being around those guys everyday basically was a wakeup call – “Rob, you’ve been asleep.  Wake up, it’s time to grow, to be excellent.”

PowerPivot, oddly, has felt like that.  My brain has been expanding again, after a period of stagnation.  More specifically, PowerPivot combined with the problems I’ve been tackling has done this.

And it flows over to other areas too.  Example:  years ago when I needed to estimate the incoming query load for the football stats project, I asked around for advice, got none, and then basically just guessed.  It was a very hollow experience.  Non-excellent.

Then recently, I was presented with essentially the same challenge.  But this time, I didn’t guess, I modeled it:  estimated how many reports (and queries per report) each user would exercise at peak, built a spreadsheet, re-taught myself the Poisson and Binomial functions, and voila – a “users per server” estimate I could believe. 

I’m positive that working with PowerPivot is the difference between the “lazy guess” mentality from before and the “it can be done” mentality today.  I love it :)

Carrot, not stick (but sometimes the carrot is too big for one sitting)

I don’t want you to interpret the above as “PowerPivot is a harsh Pai Mei figure, kicking Rob’s ass day in, day out.”

Nope, I worked with PowerPivot for months, and did things I thought were pretty damn cool, without ever stretching my brain the way I have been lately.  If you’re an Excel pro, you will find PowerPivot to be a very welcoming environment.

Excel veterans:  you will never be forced to do anything uncomfortable with PowerPivot.

In fact you will do amazing things in your first week that will actually deliver greater results than standalone Excel, and it will actually seem easier than normal Excel.  Check out the CALCULATE function and you will see what I mean.

But boy, sooner or later, it will TEMPT you to try something bigger.

You’ll be sitting there one day thinking, “Gee, I sure wish I could build an analysis that showed X.”  And then something hits you – “hey wait, I bet THAT’s what that function I looked at the other day does” or “Didn’t I see a blog post last month about something similar?”

Two hours later, you’re still heads-down over your DAX formulas and relationships, feeling like you’re 30 seconds away from a breakthrough that will change your professional life.

You might not even succeed that first day.  You may have to come back tomorrow with a fresh perspective and a clear head.

And you love it.  Every minute of it.

But that’s when you realize that you have left the reservation.  You are not in Kansas anymore.  Time to take off the training wheels.  Pick your analogy.  Make no mistake – the power of DAX in particular can challenge you immensely.  Jon Udell described the examples I’ve covered here on the blog as “magic,” and he’s right – you won’t pick up everything overnight.  You should be prepared for that.

It’s called learning.  And you’ve almost forgotten what that feels like.  It’s what drew you to Excel in the first place, years ago – that fleeting glimpse of capabilities and the results it could deliver, but also frankly because you were hooked, addicted, to mastering it.

That feeling is back :)


ALL() Revisited

February 23, 2010

 
No Filter

 

“He has no filter. He says whatever comes through his mind. He never edits himself.”

 

 


Revisiting ALL()

Yes, I’ve used ALL() a number of times already.  But I’ve never covered it directly – it’s always been a side topic to something else.  So I thought it was time I went back and made sure I had a specific post on it.

The short version is: ALL() removes filters from specific fields during a measure calculation.  It “De Niros” your measure… but in a controlled manner.

Syntax

    ALL( table_or_column, [column1], [column2], etc.)

So the first parameter is required, and can either be a single column or an entire table.

After that, you can specify as many other columns as you’d like…  as long as the first parameter didn’t specify a table. If your first  param is a table, you can’t specify additional columns.

Also note that even when specifying columns, the ALL() function requires you to always include the table name.

Lastly, all columns listed must be from the same table.

Legal Examples:

  1. ALL(Table1)
  2. ALL(Table1[Column1], Table1[Column2])

Illegal Examples:

  1. ALL([Column1])
  2. ALL(Table1, Table1[Column3])
  3. ALL(Sales[Column1], Customer[Column2])

When to use ALL() – Example #1

You never use ALL() by itself.  You always use it in the context of another function.  It’s all about setting context for a calculation.  It is not a calculation unto itself.

The simplest place to use ALL is in a measure that always shows you a grand total of something, regardless of what filters are in play.  Revisiting the Temperature Mashup demo for a moment, here’s a pivot sliced by Temperature, showing a normal Sum of Order Quantity:

Sum of Qty Only 
Now I add a measure that sets the Temperature table to ALL:

    [AllTempsQty] = CALCULATE(
                      SUM(Sales[OrderQuantity]), 
   
                    ALL(Temperature)
                    )
 

That ends up looking like:

PowerPivot Measure using ALL

(If you need a refresher on CALCULATE, which is probably the most useful function in all of DAX, check out this post.)

So, on Hot days, we sold a total of 2,245 Accessories.  And overall, across all temperatures, we sold 36,092 Accessories.

But note that the numbers are different across Category for both measures.  That’s because [AllTempsQty] did not use ALL against the Category columns (or table).

Cool.

Example #2 – % of Total

OK, but in many cases, you don’t actually want to see [AllTempsQty] in the pivot.  You just want to compare the filtered version of a measure to the unfiltered version.

So we can define something like:

  [PctOfAllTempsQty] = SUM(Sales[OrderQuantity])  / 
                       CALCULATE(
                          SUM(Sales[OrderQuantity]),
                          ALL(Temperature)
                       )

Which gives us:

Percentage of Total PowerPivot Measure using ALL function

Note that I switched Excel’s number formatting for this measure to be Percentage, keeping me from having to include * 100 in my measure.

Of course, if I wanted to keep my [AllTempsQty] measure, then I could have defined my new percent total measure as the following instead:

  [PctOfAllTempsQty] = SUM(Sales[OrderQuantity]) / 
                       [AllTempsQty]

                    

And that would have produced the same results.

Example #3 – Using ALL() in places other than CALCULATE()

If we revisit the post on derived measures, ALL() is an excellent modifier to use against an existing measure.

Let’s take a measure I defined in the Temperature Mashup, the [Qty per Day] measure:

Quantity per Day

And then we define a new measure:

  [QtyPerDayAllTemps] = [QtyPerDay](ALL(Temperature))
                 

That yields:

Using ALL function to derive another measure

You like?  I like :)


The Superheroes of DAX, and derived measures

February 19, 2010

DAX Heroes

 
 

“Did someone say DAX?”

 

 

 

I wanted to start today’s post with a quick thank-you to the guys who tirelessly answer my DAX questions.

Marius Dumitru, Howie Dickerman, and Karen Aleksanyan.  You guys rock.  Thanks again for your patience educating me.  I’ll do my best to pay it back by sharing knowledge here.

(There’s no resemblance in real life to these three pictured above.  Well, except perhaps for Mr. Furious.  But it’s just an awesome movie and had three superheroes, which is rare – superheroes tend to be packaged in even-numbered groups.)

Today’s Tip:  Deriving measures from others

Today’s tip is a short lesson but boy is it helpful. 

Let’s say you have a fairly sophisticated measure like the “Number of unique products sold at number of stores” measure that I demonstrated the other day using SUMX().  And now you want a new version of that measure that only counts a specific type of product, as opposed to all products.

Copy/Paste the original measure formula?

Do you copy/paste the formula for the original measure into a new measure to make your edits?  I recommend against it, for two reasons:

  1. You are now nesting an additional level of logic inside an already sophisticated formula – this makes things less readable and harder to debug (especially since v1 PowerPivot does not let you “trace into” a formula step by step.
  2. Maintenance-wise this is a hassle going forward.  If you ever change the base measure, you need to change all copies of it as well.  Tedious.  And it’s even worse if you forget to change one of the copies.

Better answer:  use FILTER() against the original measure

You can avoid both of those problems with the following syntax:

    [New Measure] = [Original Measure] (<Table Expression>)

The simplest example of a table expression is to use the FILTER() function.  Let’s say we want our original measure, but only to count transaction of product type = fruit:

    [New Measure] = [Original Measure] (
                      FILTER(DataTable[ProductType]=”Fruit”)
                    )

Try it out!

Trust me, it works :)   And you will love it :)

Other flavors

I’m pretty sure that any expression which returns a table is valid as the <Table Expression>. 

EX:  I used CALCULATETABLE and it also works great.  CALCULATETABLE is like FILTER but allows for any number of filter params, whereas FILTER only gives you one.

    [New Measure] = [Original Measure] (
                     CALCULATETABLE(
                      DataTable[ProductType]=”Fruit”,
                      DataTable[Weekend]=”True”
                      )
                     )

Have fun everybody.  Catch you next week.


SUMX() – The 5-point palm, exploding fxn technique

February 16, 2010

 
Pai_Mei

 

 

“AGAIN!”

-Pai Mei

 

 

 

SUMX() – the great iterator

Have you ever written an array formula in Excel?  (Don’t worry, most people haven’t).  Have you ever written a FOR loop in a programming language?  (Again, don’t worry, there’s another question coming).  Have you every repeated something over and over again, slowly building up to a final result?

That’s what SUMX() does.  It loops through a list, performs a calc at each step, and then adds up the results of each step.  That’s a pretty simple explanation, but it produces some results in pivots that are nothing short of spectacular.

Anatomy of the function

     SUMX(<Table>, <Expression>)

THE BRIDE: “What praytell, is a five-point palm, exploding function technique?”
BILL: “Quite simply, the deadliest blow in all of the analytical martial arts.”
THE BRIDE: “Did he teach you that?”
BILL: “No. He teaches no one the five-point palm, exploding function technique.”

That’s kinda how I feel about the description of SUMX in the Beta release:  “Returns the sum of an expression evaluated for each row in a table.”  It merely hints at the power within.

Oddly, the best way to show you what I mean is to start with some useless examples and then build up to useful ones.  For all examples, I will use the following simple table, Table1:

Sample Table for SUMX Table1 

Useless Example #1:  By the whole table

     SUMX(Table1, Table1[Qty])

Returns:  35, which is the total of the Qty column.  Might as well just use SUM([Qty]).

Why:  Well, it iterates over every row in Table1, and adds up [Qty] at each step, just like the description says it would.

Useless Example #2:  By a single column

     SUMX(Table1[Product], Table1[Qty])

Returns:  An Error

Why:  Table1[Product] is not a Table, it’s a Column.  And SUMX demands a Table as the first param.

Useless Example #3:  By distinct values of a column, sum another

OK, I’ll wrap the [Product] column in DISCTINT(), since that returns a single-column table:

     SUMX(DISTINCT(Table1[Product]), Table1[Qty])

Returns:  An Error

Why:  [Qty] is not a column in the single-column table DISTINCT([Product]).  Only [Product] is.  Why did I even try this?

That’s where I gave up awhile back.  Until I learned…

Almost-Useful Example:  The Second Param Can Be a Measure!

And even better, that measure CAN access other columns even if you use DISTINCT.  First let’s define a [Sum of Qty] measure:

     [Sum of Qty] = SUM(Table1[Qty])

And then re-try the previous example with the measure, not the column:

     SUMX(DISTINCT(Table1[Product]), [Sum of Qty])

Returns:  35 Yes, the total, again.   But this time, the “Why” is worth paying attention to.

Why:  Let’s step through it.  Remember, for each value of the first param, SUMX evaluates the expression in the second param, and then adds that to its running total.
Distinct Products

Step One:  SUMX evaluates DISTINCT([Table1[Product]) which yields a single-column table of the unique values in [Product]:

 

Step Two:  SUMX then filters the Table1 (not just the [Product] column!) to the first value in its single-column list, [Product] = Apples.

Table1 Filtered to Apples by SUMX
Then it evaluates the  [Sum of Qty] measure against that table, which returns 17.

Steps Three and Four:  The process repeats for Oranges and Pears, which return 13 and 5:

Table1 Filtered to Oranges by SUMX

Table1 Filtered to Pears by SUMX
Last Step:  SUMX then adds the three results it obtained:  17, 13, and 5, which yields 35.

A lot of work to get the same result that the [Sum of Qty] measure can get on its own, but now that you know how it operates, let’s do something else.

And now, the Useful Example!

Let’s define another measure, which is the count of unique stores:

     [Count of Stores] = COUNTROWS(DISTINCT(Table1[Store]))

For the overall Table1, that returns 2, because there are only 2 unique stores.

Let’s then use that measure as the second param:

     SUMX(DISTINCT(Table1[Product]), [Count of Stores])

Distinct Products

Step One:  same as previous example, get the one-column result from DISTINCT:

 

Step Two:  filter to Apples, as above:

Table1 Filtered to Apples by SUMX

…and the [Count of Stores] measure evaluates to 2 – 2 unique stores have sold Apples.

Step Three:  Oranges

Table1 Filtered to Oranges by SUMX

…again, the measure evaluates to 2.  2 unique stores sold Oranges.

Step Four:  Pears

Table1 Filtered to Pears by SUMX

…hey look, only one unique store sold Pears.  So the measure evaluates to 1 here.

Last Step:  Add them all up.  2 + 2 + 1 = 5.  SUMX returns 5.  This basically means that there are 5 unique combinations of stores and products that they sell.

Why is that useful?

Well, I can’t share the precise case I was working on, because it belongs to a reader’s business.  But trust me, you are going to find yourself wanting this sooner or later.

Things to keep in mind

  1. SUMX responds to pivot context just like anything else.  So if you slice down to just a particular year, your results will reflect only what Stores sold in that year.
  2. AVERAGEX, MINX, MAXX, and COUNTAX all work the same way.  So if you want to iterate through just like SUMX but apply a different aggregation across all of the steps, you can.  Those would return (5/3), 1, 2, and 3, respectively in our example.
  3. The fields referenced in SUMX do NOT have to be present in your pivot view.  In my case, SUMX was working against [Store] and [Product].  But my pivot could just be broken out by [Region] on rows and sliced by [Year], and the measure still works.  (I like to think of it as a stack of invisible cells underneath each pivot cell that you can see, and SUMX is rolling up a lot of logic across those invisible cells to return a simple number to the top cell you can see.)

More to come!

Yeah, I am not even done with SUMX.  Like Jules told you, it’s some serious gourmet DAX :)


DAX: I’ve been shortchanging you

February 15, 2010

You Had Me at Calculate

Mmmm! Daaaamn, Jimmie! This is some serious gourmet DAX! Usually, me and Vince would be happy with some freeze-dried Taster’s Choice right, but he springs this serious GOURMET DAX on us!

-Jules Winfield

 
 
 
What I’ve seen so far is great, and yet…

The things I have done with DAX so far are a HUGE boost to what I can do in Excel formulas alone.  Here are some of the functions I have explored to date:

  1. RELATED – a faster, simpler VLOOKUP.
  2. CALCULATE – the big Kahuna.  A version of SUMIFS that I can use in a pivot measure to remove, alter, or override pivot filters and just aggregate the source rows that I want.
  3. ALL – the ability to strip pivot filters from certain fields or tables during a measure calc, enabling very flexible custom ratios when combined with CALCULATE.
  4. DISTINCT – returns the set of unique values of a particular column within the current pivot filtering context, very useful (so far) when combined with COUNTROWS.
  5. COUNTROWS – no more need for finding the unique-valued column in a current context, you can just count the source rows that meet current filter criteria.

But I’ve seen some things over the past week that made me realize:  I’ve been lax…  about DAX.

I just found a cupboard full of “gourmet DAX”

Funny thing folks:  in many ways, I am learning right alongside of you when it comes to DAX.  When I left Redmond in August, DAX was just starting to appear in the internal builds.  So while I was getting a little bit of an advanced look, in other ways I’ve been watching the DAX movie in progress just like everyone else.

Last week, a reader asked me a series of questions basically saying “can you do this in DAX?”  These were crazy things they wanted to do – VERY useful stuff for them, and totally understandable why they wanted it.  And my initial answer was “um, no, DAX can’t do that.”

I was wrong.  DAX very much CAN do those things.  And many, many other things I had not considered.  I’m a little embarrassed by holding out on you guys, but I’ve been holding out on myself, too.

I mean, I knew I had not yet dived into the time intelligence stuff.  Other people are doing a decent job of that, and my intent was to build up to it, slow and steady.  But I was missing other things, too.

New resolution:  at least two DAX posts a week

This is a long time coming really.  It’s time to devote a much bigger chunk of my efforts toward educating everyone – myself included – on the capabilities and finer points of DAX. 

Here’s a quick preview of what’s in store for us:

  1. SUMX() – the FOR loop of DAX, kinda like Array Formulas in Excel
  2. CALCULATETABLE() – generate a custom filtered table, on the fly, and then use that as the table argument to another function
  3. Using one measure as an input to defining another – self explanatory in some ways, but you won’t believe how often this gets you out of a jam.
  4. Using a different formula at one level of a pivot vs. another – just one example of something you can do by combining some of these techniques.

Seriously, I am excited.  I’m like a kid who’s discovered a secret room in the castle.