query workflow new.jpg

In the post LOD Expressions #1 - Over (partition by)  x LOD we talked a little bit about LOD Expression and how it compares to over (partition by...).

As we said in that post, LOD expressions allows you to achieve similar results than over (partition by...).


Now we are going to understand the reason why we said "similar". In other words, we will understand the difference between them.


We will use a pretty simple example to make easier to understand.

Many of you might say this simple example can be solved with table calculation and/or data blending (as we did in the post Compare a filtered dimension to all values). And you are right, you can re-build this example with those approaches, but the intention here it to explain what happens in the back-end when you use LOD, so you can can apply on more complex cases.


So, lets start.
In our database, we have a Sales table (financial.sales_region):

Tables.png
We want to compare the sum of sales per employee with the sum of sales of the region.

This is our desired output:

Desired output.png

If your approach is to write a query using olap function, you can use this simple query:

select Category, Sub-Category, Sales, sum(sales) over (partition by Category)

from (

    select Category, Sub-Category, sum(sales) as Sales

    from table

    group by Category, Sub-Category

) A


If you are using Tableau 9.0, you can use this calculated field "By Region":

{FIXED [Region]: SUM([Sales])}


By doing that, this is the query that Tableau will create to achieve the desired output:


SELECT "t0"."employee" AS "employee",

  "t3"."__measure__1" AS "sum:calculation_86303112206550",

  "t0"."sum:sales:ok" AS "sum:sales:ok"

FROM (

  SELECT "sales_region"."employee" AS "employee",

    SUM("sales_region"."sales") AS "sum:sales:ok"

  FROM "financial"."sales_region" "sales_region"

  GROUP BY 1

) "t0"

  INNER JOIN (

  SELECT SUM("t2"."__measure__0") AS "__measure__1",

    "t1"."employee" AS "employee"

  FROM (

    SELECT "sales_region"."region" AS "region",

      "sales_region"."employee" AS "employee"

    FROM "financial"."sales_region" "sales_region"

    GROUP BY 1,

      2

  ) "t1"

    INNER JOIN (

    SELECT SUM("sales_region"."sales") AS "__measure__0",

      "sales_region"."region" AS "region"

    FROM "financial"."sales_region" "sales_region"

    GROUP BY 2

  ) "t2" ON (("t1"."region" = "t2"."region") OR (("t1"."region" IS NULL) AND ("t2"."region" IS NULL)))

  GROUP BY 2

) "t3" ON (("t0"."employee" = "t3"."employee") OR (("t0"."employee" IS NULL) AND ("t3"."employee" IS NULL)))

query workflow.png

As you can see, they have different technical solution.


With Tableau's approach you can interact direct with those sub-queries, which gives you some advantages.
For example, you want to exclude the Employee A from your analysis.

To do that, you will use a quick filter.

filter.png


When you add a filter, you can whether or not use it as a context filter.

Depending on which option you chose, you will interact with specifics sub-queries.


Not using as context filter

If you did not add the filter to context, Tableau will exclude Employee A from your output, but will keep it on the calculation of the Region.

Which means that Employee A will still be part of the "Sum os Sales by Region".

 

This is the query that Tableau will perform:

SELECT "t0"."employee" AS "employee",

  "t3"."__measure__1" AS "sum:calculation_86303112206550",

  "t0"."sum:sales:ok" AS "sum:sales:ok"

FROM (

  SELECT "sales_region"."employee" AS "employee",

    SUM("sales_region"."sales") AS "sum:sales:ok"

  FROM "financial"."sales_region" "sales_region"

  WHERE (NOT ("sales_region"."employee" = 'A'))

  GROUP BY 1

) "t0"

  INNER JOIN (

  SELECT SUM("t2"."__measure__0") AS "__measure__1",

    "t1"."employee" AS "employee"

  FROM (

    SELECT "sales_region"."region" AS "region",

      "sales_region"."employee" AS "employee"

    FROM "financial"."sales_region" "sales_region"

    WHERE (NOT ("sales_region"."employee" = 'A'))

    GROUP BY 1,

      2

  ) "t1"

    INNER JOIN (

    SELECT SUM("sales_region"."sales") AS "__measure__0",

      "sales_region"."region" AS "region"

    FROM "financial"."sales_region" "sales_region"

    GROUP BY 2

  ) "t2" ON (("t1"."region" = "t2"."region") OR (("t1"."region" IS NULL) AND ("t2"."region" IS NULL)))

  GROUP BY 2


) "t3" ON (("t0"."employee" = "t3"."employee") OR (("t0"."employee" IS NULL) AND ("t3"."employee" IS NULL)))

query workflow with filter.png
As you can see, the filter was not included in sub-query "t2", because that is the sub-query which generate the sales by region.



Using context filter

If you add the filter to context, Tableau will include the filter "Employee <> 'A'" to your whole analysis, by doing that, the sales by region will no longer include the sales of Employee A.

 

This is the query generated:

SELECT "t0"."employee" AS "employee",

  "t3"."__measure__1" AS "sum:calculation_86303112206550",

  "t0"."sum:sales:ok" AS "sum:sales:ok"

FROM (

  SELECT "sales_region"."employee" AS "employee",

    SUM("sales_region"."sales") AS "sum:sales:ok"

  FROM "financial"."sales_region" "sales_region"

  WHERE (NOT ("sales_region"."employee" = 'A'))

  GROUP BY 1

) "t0"

  INNER JOIN (

  SELECT SUM("t2"."__measure__0") AS "__measure__1",

    "t1"."employee" AS "employee"

  FROM (

    SELECT "sales_region"."employee" AS "employee",

      "sales_region"."region" AS "region"

    FROM "financial"."sales_region" "sales_region"

    WHERE (NOT ("sales_region"."employee" = 'A'))

    GROUP BY 2,

      1

  ) "t1"

    INNER JOIN (

    SELECT "sales_region"."region" AS "region",

      SUM("sales_region"."sales") AS "__measure__0"

    FROM "financial"."sales_region" "sales_region"

    WHERE (NOT ("sales_region"."employee" = 'A'))

    GROUP BY 1

  ) "t2" ON (("t1"."region" = "t2"."region") OR (("t1"."region" IS NULL) AND ("t2"."region" IS NULL)))

  GROUP BY 2


) "t3" ON (("t0"."employee" = "t3"."employee") OR (("t0"."employee" IS NULL) AND ("t3"."employee" IS NULL)))

query workflow with context filter.png

Now, all the sub-queries have the filter "Employee <> 'A'".


Visit my personal blog Data Visualization & Preparation tips.