Visitar URL original
feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [SIP-216] by rusackas · Pull Request #41184 · apache/superset · GitHub
Skip to content

feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [SIP-216] - #41184

Merged
rusackas merged 13 commits into
apache:masterfrom
rusackas:sip-non-additive-totals
Jul 22, 2026
Merged

rusackas merged 13 commits into
apache:masterfrom
rusackas:sip-non-additive-totals

Conversation

@rusackas

@rusackas rusackas commented Jun 18, 2026 •

Copy link
Copy Markdown
Member

SUMMARY

Proof-of-concept for [SIP-216] / #41463 — fixing one of Superset's longest-standing correctness gaps: totals and subtotals are wrong for non-additive metrics (ratios, COUNT_DISTINCT, AVG, percentiles, and "Percentage metrics") in both the Pivot Table and the regular Table chart.

See #41463 for the full proposal, motivation, and rejected alternatives. This PR is the working implementation referenced throughout that SIP.

Core principle: totals are computed by the database at the grouping granularity, never by re-aggregating already-aggregated cells. A SQL-aggregate metric is correct at any grouping level if the same expression is evaluated grouped at that level, so no formula language is needed.

What's here (consolidates #25747, #32260, #38674, #36165, #37627, #34350/#34425/#34426):

  • Pivot Table — database-computed rollup levels via a single GROUPING SETS query (native where the engine supports it, per-level fallback otherwise); the react-pivottable aggregator becomes a passthrough that places DB-computed values. Removes the now-meaningless "Aggregation function" control.
  • Table chart — retains post-processing on the summary query so percent/contribution columns are recomputed instead of dropped (Percentage metrics column display only zero value #37627/Page table calculation error #34350).
  • Performance — additive fast-path (single query + client-side synthesis), supports_grouping_sets engine capability, query-level pruning to only displayed totals.

Builds on prior art in #34592 (salvages its rollup-combination generator). Out of scope: #39223.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

A rows=[gender, state] pivot with a ratio metric SUM(CASE WHEN state='CA' …)/SUM(num):

  • Before: grand total / subtotal show the sum of per-row percentages (e.g. 100%+).
  • After: grand total and the per-gender subtotal both show the DB-computed 11%, returned by a single GROUPING SETS query (verified in-app on Postgres; 25 rows = 22 leaf + 2 subtotals + 1 grand total).

TESTING INSTRUCTIONS

  1. Pivot a non-additive metric (e.g. a ratio SUM(a)/SUM(b) or COUNT_DISTINCT) with row totals/subtotals enabled; confirm the totals reflect the metric recomputed at each level, not the sum of cells.
  2. Table chart with a "Percentage metrics" column + "Show summary"; confirm the percent column appears in the summary row.
  3. Verify additive metrics (SUM/COUNT) are unchanged.

Unit + integration tests cover the rollup synthesis, GROUPING SETS clause/marker/split helpers (native + SQLite fallback), additivity detection, and the table summary path.

ADDITIONAL INFORMATION

The SIP (#41463) passed its vote on the dev@ list.

@netlify

netlify Bot commented Jun 18, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for superset-docs-preview ready!

Name Link
🔨 Latest commit e417294
🔍 Latest deploy log https://app.netlify.com/projects/superset-docs-preview/deploys/6a600dba6706d9000894fc0c
😎 Deploy Preview https://deploy-preview-41184--superset-docs-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@codecov

codecov Bot commented Jun 18, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.14079% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.19%. Comparing base (9c08240) to head (e417294).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...hart-pivot-table/src/react-pivottable/utilities.ts 88.70% 7 Missing ⚠️
...s/plugin-chart-pivot-table/src/PivotTableChart.tsx 69.23% 4 Missing ⚠️
superset/common/query_context_processor.py 87.50% 2 Missing and 2 partials ⚠️
...gin-chart-pivot-table/src/plugin/transformProps.ts 90.00% 2 Missing ⚠️
.../plugin-chart-pivot-table/src/plugin/buildQuery.ts 94.11% 1 Missing ⚠️
...s/plugin-chart-pivot-table/src/plugin/utilities.ts 98.85% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #41184      +/-   ##
==========================================
+ Coverage   65.13%   65.19%   +0.06%     
==========================================
  Files        2789     2791       +2     
  Lines      157538   157761     +223     
  Branches    35864    35931      +67     
==========================================
+ Hits       102611   102858     +247     
+ Misses      52956    52931      -25     
- Partials     1971     1972       +1     
Flag Coverage Δ
hive 38.74% <35.06%> (-0.01%) ⬇️
javascript 71.10% <92.50%> (+0.02%) ⬆️
mysql 57.70% <85.71%> (?)
postgres 57.74% <67.53%> (+0.03%) ⬆️
presto 40.65% <38.96%> (-0.01%) ⬇️
python 59.14% <94.80%> (+0.09%) ⬆️
sqlite 57.37% <85.71%> (+0.05%) ⬆️
unit 100.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@rusackas rusackas changed the title [SIP] Correct totals/subtotals for non-additive metrics (Table + Pivot) feat(pivot-table): correct non-additive totals/subtotals via DB rollup [POC for #41463] Jun 26, 2026
@rusackas
rusackas force-pushed the sip-non-additive-totals branch from b28a7e6 to 89a40db Compare June 26, 2026 22:14
@rusackas rusackas changed the title feat(pivot-table): correct non-additive totals/subtotals via DB rollup [POC for #41463] feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [POC for #41463] Jul 2, 2026
@rusackas rusackas changed the title feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [POC for #41463] feat(table/pivot-table): correct non-additive totals/subtotals via DB rollup [POC for SIP-216] Jul 2, 2026
@rusackas

rusackas commented Jul 2, 2026

Copy link
Copy Markdown
Member Author

The SIP is up for a vote on the dev@ list... please VOTE if you wanna see this happen

@rusackas
rusackas requested a review from SBIN2010 July 10, 2026 01:33
@rusackas
rusackas marked this pull request as ready for review July 10, 2026 01:33
@dosubot dosubot Bot added change:backend Requires changing the backend change:frontend Requires changing the frontend viz:charts:pivot Related to the Pivot Table charts viz:charts:table Related to the Table chart labels Jul 10, 2026
@aminghadersohi

Copy link
Copy Markdown
Contributor

Following up on the earlier review: CI is currently red on this head (9a30e5003e88) in a way that looks like a real regression, not a flake.

sharded-jest-tests (6) fails 4 assertions in plugin-chart-pivot-table/test/TableRenderer.test.tsx (all about the pvtRowLabelLast class that marks the last data row before a totals row): dataRows[dataRows.length - 1] comes back undefined, and the "spanning" row-label header cell isn't found where expected.

That test file isn't part of this PR's own diff — it's an existing test that predates the rebase this branch picked up — and it was passing at the SHA this review was originally done against, so something in this PR's rewrite of the row/rollup logic is the likely cause rather than any of the small follow-up commits since (those only touch a control description, an unrelated table-chart test import, and a docstring).

My guess, not yet confirmed: processRecord()'s rewrite of how rows/subtotals get keyed and slotted (react-pivottable/utilities.ts) changed rowKeys/visibleRowCount in a way that breaks the last-row detection in TableRenderers.tsx's pvtRowLabelLast logic. Worth a look before merge — this is separate from the total-value correctness reviewed earlier, which still looks solid.

@bito-code-review

bito-code-review Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #49d658

Actionable Suggestions - 0
Review Details
  • Files reviewed - 1 · Commit Range: d6805e9..9a30e50
    • superset/common/query_context_processor.py
  • Files skipped - 0
  • Tools
    • MyPy (Static Code Analysis) - ✔︎ Successful
    • Astral Ruff (Static Code Analysis) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

…leaf level

A result frame without GROUPING() marker columns (any query that never
applied the grouping_sets extra) had every row discarded by the marker
filter in splitGroupingSetsResult, rendering the chart completely blank
-- surfaced by the pre-existing TableRenderer.test.tsx fixtures. Fall
back to attributing all rows to the leaf level with empty rollup frames.

Also replaces a raw NUL byte in the GROUP_SEP literal with the \u0000
escape so git stops treating utilities.ts as a binary file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@rusackas

Copy link
Copy Markdown
Member Author

Thanks for catching this, @aminghadersohi. Turned out splitGroupingSetsResult was dropping every row when the frame had no GROUPING() marker columns (any query that never hit the grouping-sets extra), so it now falls back to attributing them to the leaf level. sharded-jest-tests (6) is green on the current head.

@bito-code-review

bito-code-review Bot commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

Code Review Agent Run #ca96b0

Actionable Suggestions - 0
Filtered by Review Rules

Bito filtered these suggestions based on rules created automatically for your feedback. Manage rules.

  • superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/utilities.test.ts - 1
Review Details
  • Files reviewed - 1 · Commit Range: 9a30e50..e417294
    • superset-frontend/plugins/plugin-chart-pivot-table/test/plugin/utilities.test.ts
  • Files skipped - 0
  • Tools
    • Eslint (Linter) - ✔︎ Successful
    • Whispers (Secret Scanner) - ✔︎ Successful
    • Detect-secrets (Secret Scanner) - ✔︎ Successful

Bito Usage Guide

Commands

Type the following command in the pull request comment and save the comment.

  • /review - Manually triggers a full AI review.

  • /pause - Pauses automatic reviews on this pull request.

  • /resume - Resumes automatic reviews.

  • /resolve - Marks all Bito-posted review comments as resolved.

  • /abort - Cancels all in-progress reviews.

Refer to the documentation for additional commands.

Configuration

This repository uses Superset You can customize the agent settings here or contact your Bito workspace admin at evan@preset.io.

Documentation & Help

AI Code Review powered by Bito Logo

@rusackas

Copy link
Copy Markdown
Member Author

Thanks for digging in, @aminghadersohi. Good lead... though it turned out not to be the last-row logic at all. splitGroupingSetsResult attributes each row to a rollup level via the GROUPING() marker columns, and the old test fixtures feed rows with no markers, so every row got filtered out and the table rendered empty. Fixed by treating marker-less results as leaf-level data (blank totals cells beat a blank chart), with a unit test to pin it down, and merged current master while I was in there. CI's green again.

@aminghadersohi aminghadersohi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified at HEAD e417294: CI fully green, non-additive DB-rollup total logic correct (SUM/ratio totals computed per grouping level, not summed client-side), GROUPING SETS query construction is parameterized via SQLAlchemy (no injection surface), and the earlier TableRenderer.test.tsx/pvtRowLabelLast regression is fixed (splitGroupingSetsResult now handles marker-less result frames). All review threads resolved.

@rusackas

Copy link
Copy Markdown
Member Author

Been trying to get reviews on this for over a month by nagging people on slack, but I'll take the approval (thanks!) and lack of bot or human complaints as good enough... merging during the breaking change window to get it into 7.0, and will happily make touchups/fixes as needed when people do more testing than I already have.

@jermainebarteauix81-droid

Copy link
Copy Markdown

SUMMARY

Proof-of-concept for [SIP-216] / #41463 — fixing one of Superset's longest-standing correctness gaps: totals and subtotals are wrong for non-additive metrics (ratios, COUNT_DISTINCT, AVG, percentiles, and "Percentage metrics") in both the Pivot Table and the regular Table chart.

See #41463 for the full proposal, motivation, and rejected alternatives. This PR is the working implementation referenced throughout that SIP.

Core principle: totals are computed by the database at the grouping granularity, never by re-aggregating already-aggregated cells. A SQL-aggregate metric is correct at any grouping level if the same expression is evaluated grouped at that level, so no formula language is needed.

What's here (consolidates #25747, #32260, #38674, #36165, #37627, #34350/#34425/#34426):

  • Pivot Table — database-computed rollup levels via a single GROUPING SETS query (native where the engine supports it, per-level fallback otherwise); the react-pivottable aggregator becomes a passthrough that places DB-computed values. Removes the now-meaningless "Aggregation function" control.
  • Table chart — retains post-processing on the summary query so percent/contribution columns are recomputed instead of dropped (Percentage metrics column display only zero value #37627/Page table calculation error #34350).
  • Performance — additive fast-path (single query + client-side synthesis), supports_grouping_sets engine capability, query-level pruning to only displayed totals.

Builds on prior art in #34592 (salvages its rollup-combination generator). Out of scope: #39223.

BEFORE/AFTER SCREENSHOTS OR ANIMATED GIF

A rows=[gender, state] pivot with a ratio metric SUM(CASE WHEN state='CA' …)/SUM(num):

  • Before: grand total / subtotal show the sum of per-row percentages (e.g. 100%+).
  • After: grand total and the per-gender subtotal both show the DB-computed 11%, returned by a single GROUPING SETS query (verified in-app on Postgres; 25 rows = 22 leaf + 2 subtotals + 1 grand total).

TESTING INSTRUCTIONS

  1. Pivot a non-additive metric (e.g. a ratio SUM(a)/SUM(b) or COUNT_DISTINCT) with row totals/subtotals enabled; confirm the totals reflect the metric recomputed at each level, not the sum of cells.
  2. Table chart with a "Percentage metrics" column + "Show summary"; confirm the percent column appears in the summary row.
  3. Verify additive metrics (SUM/COUNT) are unchanged.

Unit + integration tests cover the rollup synthesis, GROUPING SETS clause/marker/split helpers (native + SQLite fallback), additivity detection, and the table summary path.

ADDITIONAL INFORMATION

The SIP (#41463) passed its vote on the dev@ list.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:backend Requires changing the backend change:frontend Requires changing the frontend plugins size/XXL viz:charts:pivot Related to the Pivot Table charts viz:charts:table Related to the Table chart

Projects

Status: Completed

Development

Successfully merging this pull request may close these issues.

Rename "Subtotal" to "Subvalue" in Pivot Tables

4 participants