Debugging Calculations - Tableau

  1. Which calculation correctly implements the intended logic using Tableau's CASE syntax?
    Answer: CASE [Region] WHEN "East" THEN "E" WHEN "West" THEN "W" ELSE "Other" END Tableau's CASE statement has two distinct syntactic forms, and mixing them up is one of the most common calculation errors you'll encounter. The form in the passage — CASE WHEN [Region] = "East" THEN... — is actually an IIF/IF-THEN style pattern, not valid CASE syntax in Tableau. Knowing the difference is exactly what this question tests. Tableau's CASE syntax requires you to place the field being evaluated immediately after the word CASE, then list only the comparison values (not full boolean expressions) after each WHEN. Answer A does this correctly: CASE [Region] WHEN "East" THEN "E" WHEN "West" THEN "W" ELSE "Other" END. Tableau compares [Region] to each value in sequence and returns the matching result — clean, valid, and complete. B is a structural inversion — it places the field after WHEN and tries to embed the comparison inside the THEN clause, which is backwards and nonsensical syntax. C uses the correct opening (CASE [Region]) but then breaks the rule by writing full boolean expressions ([Region] = "East") after WHEN, which is only valid in IF statements, not CASE. It also omits the ELSE clause. D wraps the entire expression in parentheses and uses commas as delimiters, resembling a function call — Tableau's CASE is a control-flow statement, not a function, so this syntax is entirely invalid. A useful mental shortcut: in Tableau's CASE, think "CASE [field], WHEN [value]" — you name the field once upfront, then only list values after each WHEN, never full conditions.
  2. Which revision uses the correct Tableau function syntax and preserves the intended date comparison?
    Answer: IF DATEDIFF("day", [Order Date], [Ship Date]) > 2 THEN "Late" ELSE "On Time" END When working with Tableau's date functions, argument order is everything — getting it wrong causes errors even when your logic is sound. The function you need here is DATEDIFF, which calculates the difference between two dates. Tableau's required syntax is **DATEDIFF(date_part, start_date, end_date)** — the date part string comes first, followed by the earlier date, then the later date. The result is how many units of date_part elapsed from start to end. To detect late shipments, you want [Ship Date] minus [Order Date], meaning [Order Date] is your start and [Ship Date] is your end. That makes option C — DATEDIFF("day", [Order Date], [Ship Date]) > 2 — the correct revision. It uses the right syntax and returns a positive number when shipping took more than two days, preserving the intended logic. Option A flips the two date fields, placing [Ship Date] as the start and [Order Date] as the end. This produces a negative number for late orders, so the > 2 comparison would never catch them — it silently reverses your logic. Option B keeps [Order Date] and [Ship Date] in roughly the right order but buries "day" in the middle, which violates the required argument sequence and produces an error. Option D uses DATEADD entirely, which adds a time interval to a single date rather than measuring the gap between two dates — it's the wrong function for this task altogether. A handy memory device: think "DATEDIFF = Part, Start, End" — the date part is always first, just like how you'd say "measured in days, from A to B."
  3. Which revision best resolves the error while preserving the stated labeling requirement?
    Answer: IF [Profit] > 0 THEN "Profit" ELSE "No Profit" END Whenever you see a calculated field producing a "result types do not match" error in Tableau, your first instinct should be to check whether every branch of your IF/THEN/ELSE statement returns the same data type. Tableau requires that all possible return values be consistent — all strings, all numbers, or all dates. You cannot mix types across branches. In the original formula, the THEN branch returns "Profit" (a string) while the ELSE branch returns 0 (an integer). That type mismatch is exactly what triggers the error. Option B — IF [Profit] > 0 THEN "Profit" ELSE "No Profit" END — fixes this cleanly by returning a string in both branches, and it matches the stated requirement of labeling records as either "Profit" or "No Profit." This is the correct answer. Option A converts the profit number to a string with STR([Profit]) in the THEN branch, but the ELSE still returns 0 (an integer), so the type mismatch persists. It also fails the labeling requirement entirely. Option C has the same fundamental problem in reverse: 1 is an integer and "No Profit" is a string — still a type conflict, still broken. Option D wraps the condition in SUM(), which is an aggregation function and would cause a separate error when mixing aggregated and non-aggregated fields; it also keeps the 0 in the ELSE branch, leaving the original type mismatch unresolved. As a study tip, whenever you write an IF statement in Tableau, mentally audit every branch and ask: "Do all my return values share the same data type?" If not, use type-conversion functions like STR() or INT() to align them — just make sure every branch is converted, not just one.
  4. Which revision both compiles and produces the correct result for marks containing mixed order statuses?
    Answer: SUM(IF [Status] = "Returned" THEN [Sales] ELSE 0 END) Whenever you see a calculation that mixes a row-level comparison with an aggregate function in Tableau, ask yourself: where does the aggregation happen? Tableau requires that within a single expression, you can't mix unaggregated fields with aggregate functions at the same level — either everything gets aggregated, or nothing does. The correct fix is A: SUM(IF [Status] = "Returned" THEN [Sales] ELSE 0 END). Here, the IF condition evaluates row by row before aggregation occurs — each individual row either contributes its [Sales] value or contributes 0. Then SUM() wraps the entire expression, aggregating those row-level results cleanly. This correctly totals sales only from returned rows, even within marks that contain mixed statuses. B fails because it still mixes an aggregate (ATTR([Status])) with an aggregate (SUM([Sales])) inside an IF statement — but the deeper problem is logical: ATTR() returns a single value for the whole mark, so if a mark contains both returned and non-returned orders, ATTR([Status]) returns * (null/asterisk), making the condition false and returning 0 even when some sales were returned. It compiles but gives wrong results for mixed marks. C compounds the errors from B — using ATTR() inside a SUM() wrapper creates an aggregate-within-aggregate error, and the mixed-status logic problem remains. D attempts to fix the original by wrapping 0 in SUM(), but SUM([Sales]) inside an IF is still an aggregate nested inside a non-aggregate condition, reproducing the original error. Your study tip: always push the IF logic inside the aggregate function — SUM(IF ... THEN [field] ELSE 0 END) is the standard Tableau pattern for conditional aggregation.
  5. Which replacement resolves the error and preserves the required definition of overall profit margin?
    Answer: SUM([Profit]) / SUM([Sales]) Whenever Tableau throws an aggregation error, your first instinct should be to check whether you're nesting an aggregation inside another aggregation — that's almost always the culprit. The attempted formula SUM([Profit] / SUM([Sales])) tries to use SUM([Sales]) — an aggregate — inside another SUM(...). Tableau evaluates the inner SUM([Sales]) first, producing a single number, and then tries to divide each row-level [Profit] value by that aggregate before summing. Mixing row-level fields and aggregates within the same expression is illegal in Tableau's calculation engine, hence the error. Option A, SUM([Profit]) / SUM([Sales]), is the correct fix. It computes total profit and total sales independently, then divides the two aggregates — exactly the definition of overall profit margin. This is both syntactically valid and mathematically faithful to what the analyst intended. Option B, SUM([Profit] / [Sales]), avoids the nesting error, but it calculates a per-row profit ratio first and then sums those ratios. That produces a meaningless cumulative sum of individual margins, not an overall margin — a subtle but critical logical flaw. Option C uses AVG([Profit]) in the numerator, which divides total profit by the number of rows before dividing by total sales. This distorts the numerator and will not equal total profit divided by total sales. Option D mirrors that problem in the denominator: AVG([Sales]) is not the same as SUM([Sales]), so the ratio won't reflect true overall margin. Study tip: In Tableau, always keep aggregations at the same "level" — aggregate divided by aggregate. If you see a nested aggregate, that's your signal to restructure, not to work around it.
  6. Which revision applies the segment logic at the correct level and then aggregates the result?
    Answer: SUM(CASE [Segment] WHEN "Consumer" THEN [Sales] WHEN "Corporate" THEN [Profit] ELSE 0 END) Whenever you see a CASE expression mixing row-level fields with aggregate functions in Tableau, the key question is: where does the aggregation belong? Tableau requires that an expression be either entirely row-level or entirely aggregate — you cannot mix the two in the same calculation. The root problem in the original formula is that SUM([Sales]) and SUM([Profit]) are aggregates sitting inside a CASE that also references the row-level field [Segment]. Tableau sees aggregate and non-aggregate logic in the same expression and throws an error. The fix is to let CASE operate at the row level — selecting which raw value to pick per row based on Segment — and then wrap the entire expression in a single SUM() to aggregate afterward. That's exactly what C does: SUM(CASE [Segment] WHEN "Consumer" THEN [Sales] WHEN "Corporate" THEN [Profit] ELSE 0 END). The CASE runs first across individual rows, returning a row-level number, and SUM rolls those numbers up. This is correct. A is wrong because ATTR([Segment]) is itself an aggregate, which means you still have an aggregate-inside-non-aggregate conflict — and there's no outer SUM to finalize the result anyway. B attempts to keep aggregates inside the CASE and even adds SUM(0) on the ELSE branch, but mixing SUM([Sales]) and SUM([Profit]) inside a CASE that references a non-aggregated dimension still triggers the same mixed-aggregate error. D wraps a valid row-level CASE in SUM(), which sounds like C, but using ATTR([Segment]) inside an expression that's already being aggregated by the outer SUM creates another aggregate-nesting conflict. The study tip to remember: CASE goes inside SUM, not the other way around. Apply logic row-by-row first, then aggregate once on the outside.
  7. Which calculation produces an aggregate/non-aggregate mixing error?
    Answer: SUM([Sales]) > [Sales Target] When working with calculated fields in Tableau, you need to understand the distinction between aggregate and non-aggregate expressions. An aggregate expression applies a function like SUM() or AVG() across multiple rows, while a non-aggregate expression evaluates at the row level. Tableau will throw a mixing error whenever you compare an aggregate value directly to a non-aggregate field in the same calculation — because they operate at fundamentally different granularities. Option D, SUM([Sales]) > [Sales Target], is the culprit. SUM([Sales]) is an aggregate, but [Sales Target] is a raw data source field — non-aggregate. Tableau cannot reconcile these two levels in a single expression, producing the mixing error. Option A is valid because [Sales Target Parameter] is a parameter, not a data source field. Parameters exist outside the data and are treated as constant scalar values, meaning they're compatible with aggregates without causing a mixing error. Option B is also valid — SUM([Sales]) and AVG([Sales Target]) are both aggregates, so they operate at the same level and compare cleanly. Option C avoids the error entirely because both [Sales] and [Sales Target] are non-aggregate row-level fields, keeping the calculation consistent. A useful rule of thumb: parameters play by different rules than fields. Parameters are always scalar and never cause mixing errors, no matter what you compare them to. When you see a field pulled directly from the data source sitting next to an aggregate function, that's your signal to flag a potential mixing error. On the exam, carefully check whether each operand is aggregate, non-aggregate, or a parameter before evaluating the calculation's validity.
  8. Which revision resolves the error while preserving the intended row-level comparison?
    Answer: IF [Sales] > { FIXED : AVG([Sales]) } THEN "Above" ELSE "Below" END Whenever you see a calculation mixing row-level fields like [Sales] with aggregate functions like AVG([Sales]), Tableau throws an aggregate/non-aggregate error because it can't resolve the two different levels of detail in the same expression. The fix requires bringing both sides of the comparison to the same level — and the cleanest way to do that while keeping the comparison row-level is a Level of Detail (LOD) expression. Answer A is correct because { FIXED : AVG([Sales]) } is a LOD expression that computes the grand average across the entire data source and returns it as a constant value attached to every row. This means [Sales] (row-level) is now being compared to a fixed scalar — no level-of-detail mismatch, and every individual order is correctly labeled relative to the overall average. Answer B aggregates [Sales] with SUM(), which eliminates the error but destroys the row-level intent — you're now comparing an aggregate to an aggregate, which makes sense only in a view with dimensions, not per-order. Answer C uses WINDOW_AVG, a table calculation that operates on aggregated query results, not on raw row-level data. It can't access [Sales] as a non-aggregate inside an IF statement and still doesn't solve the comparison at the row level. Answer D compares AVG([Sales]) to itself — both sides are identical, so the result is always "Above" (since the condition is always true), which is logically meaningless. A reliable study tip: when you need to compare a row-level field against a data-source-wide aggregate, reach for { FIXED : AGG([Field]) } — it collapses the aggregate into a constant that plays nicely at row level.
  9. Which revision correctly calculates cumulative sales as a proportion of the department target?
    Answer: RUNNING_SUM(SUM([Sales])) / ATTR([Department Target]) Whenever you encounter a table calculation mixed with a field reference in Tableau, ask yourself: is every component of the expression operating at the same level of aggregation? Tableau requires that you either fully aggregate a field or wrap it in a function like ATTR() — you can't mix a table calculation (which operates on already-aggregated values) with a raw field reference. In this scenario, RUNNING_SUM(SUM([Sales])) is a table calculation acting on an aggregate, which is correct. The problem is dividing by [Department Target] directly — Tableau sees this as mixing an aggregate expression with a non-aggregate field, triggering the error. The fix is wrapping [Department Target] in ATTR(), which returns the field's value when it's identical across all rows in the partition (exactly the case here, since the target is constant per department). That makes B — RUNNING_SUM(SUM([Sales])) / ATTR([Department Target]) — the correct revision. A is wrong because RUNNING_SUM([Sales]) skips the required inner aggregation. RUNNING_SUM expects an aggregate expression as its argument; without SUM(), Tableau cannot evaluate it properly. C is the original broken formula — it still divides by the raw [Department Target] field, which is exactly what caused the aggregate/non-aggregate error in the first place. D embeds the division inside RUNNING_SUM, meaning it accumulates a ratio at each row rather than computing the cumulative sum first and then dividing once — logically incorrect for a proportion of a fixed target. Study tip: Remember that ATTR() is your bridge between a constant dimension value and an aggregate context — if a field is guaranteed to be the same across a partition, ATTR() safely lifts it into an aggregate expression without distorting the logic.
  10. Which revision resolves the error without inflating the regional denominator when multiple rows underlie a mark?
    Answer: SUM([Sales]) / MIN({ FIXED [Region] : SUM([Sales]) }) Whenever you mix an aggregate expression like SUM([Sales]) with a Level of Detail (LOD) expression in a calculated field, Tableau requires the LOD result to also be wrapped in an aggregate function — otherwise you get the "cannot mix aggregate and non-aggregate" error. The key insight is that an LOD expression returns a row-level value from Tableau's perspective, even though it computed something at a fixed grain. To use it alongside an aggregate, you must aggregate it. The correct answer is D. Wrapping the LOD in MIN() satisfies the aggregation requirement. Because { FIXED [Region] : SUM([Sales]) } returns the same single value for every row belonging to a given region, MIN(), MAX(), and SUM() of that constant within the region all return that same constant — so the denominator is never inflated. You get the correct per-mark ratio: SUM([Sales]) / MIN({ FIXED [Region] : SUM([Sales]) }). A is wrong because { FIXED : AVG([Sales]) } computes a grand-average across the entire dataset, not the regional total — the denominator is entirely incorrect. B is wrong because SUM({ FIXED [Region] : SUM([Sales]) }) does solve the aggregation error syntactically, but SUM() of a constant repeated across multiple rows multiplies that constant by the row count, inflating the denominator whenever more than one row underlies a mark. C is wrong because [Sales] is a non-aggregate dimension value, making the numerator non-aggregate while the LOD is also non-aggregate — the aggregation error persists, and the ratio would be computed at row level rather than mark level. Your study tip: when an LOD appears in a calculation alongside an aggregate, always wrap the LOD in MIN() or MAX() (never SUM() or AVG()) to avoid unintentionally multiplying or averaging a fixed constant.

Start this quiz