Skip to content

CRM Analytics. Opportunity dataset grain. Keep pipeline totals honest.

What this means for your store

Grain is simply: what does one row represent? Sum Amount on a dataset where each row is one opportunity and the pipeline chart is trustworthy. Join OpportunityLineItem without aggregating first and every SKU line repeats the parent deal value - the usual break when wholesale teams mix quote lines with header totals on the same lens.

Scenario on a real storefront

A UK office-furniture wholesaler wants stage charts at deal level and a separate product attach view at SKU level. Two datasets, two grains - not one bloated join:

# SAQL - roll up to opportunity grain before the dashboard
q = load "opp_line_items_raw";
q = group q by 'OpportunityId';
q = foreach q generate
    'OpportunityId' as 'OppId',
    sum('TotalPrice') as 'LineRevenue',
    max('Amount') as 'OppAmount',   -- same on every line; max, not sum
    max('StageName') as 'Stage',
    max('CloseDate') as 'CloseDate';
q = filter q by 'Stage' != "Closed Lost";

# Lens: bar on Stage, measure sum(OppAmount)
# Trap: sum(LineRevenue) != OppAmount when header discount lives on Opportunity only

What to do next

  • Pin a one-line note on the app home: “Pipeline lens = opp_grain; SKU mix = opp_line_grain.”
  • When ecommerce orders land as Opportunity + Order, pick one revenue column - summing both in the same widget inflates closed-won.
  • Before org-wide rollout, filter SAQL to one known deal: row count for that OpportunityId must be exactly 1.

Bottom line

Wrong grain silently doubles pipeline. Aggregate to opportunity level for stage and forecast lenses; spin up a line-item dataset when reps need SKU detail.