{
  "category": "Lookup and reference functions",
  "display_name": "PIVOTBY",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.PIVOTBY",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 1,454 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 1,454 recorded answers",
    "workbook_corpus": {
      "cells": 1454,
      "matched": 1454
    }
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/grouping.rs#L796-L796",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/grouping.rs#L577-L605",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/grouping.rs#L607-L654",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/grouping.rs#L656-L791"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/comparison::numbers",
        "catalogue/comparison::in_band",
        "catalogue/comparison::Rounded::up",
        "catalogue/comparison::Roundings::of",
        "catalogue/comparison::Roundings::disjoint",
        "catalogue/comparison::texts",
        "catalogue/comparison/collation::compare",
        "catalogue/comparison/collation::weighed",
        "catalogue/comparison/collation::measured_iteration_extension",
        "catalogue/comparison/sort_key::table",
        "catalogue/comparison/sort_key::decode64",
        "catalogue/comparison/sort_key::Reader::byte",
        "catalogue/comparison/sort_key::Reader::varint",
        "catalogue/comparison/sort_key::Reader::done",
        "catalogue/comparison/sort_key::in_ranges",
        "catalogue/comparison/sort_key::build",
        "catalogue/comparison/sort_key::han_base",
        "catalogue/comparison/sort_key::derive",
        "catalogue/comparison/sort_key::shared_jamo_tails",
        "catalogue/comparison/sort_key::ordinary_jamo_prefix",
        "catalogue/comparison/sort_key::independent_jamo_suffix",
        "catalogue/comparison/sort_key::jamo_leading_primary",
        "catalogue/comparison/sort_key::leading_order",
        "catalogue/comparison/sort_key::Before::separate_special",
        "catalogue/comparison/sort_key::Gathered::kana",
        "catalogue/comparison/sort_key::Gathered::unit",
        "catalogue/comparison/sort_key::parts",
        "catalogue/comparison/sort_key::diacritic_order",
        "catalogue/comparison/sort_key::diacritics",
        "catalogue/grouping::Table::height",
        "catalogue/grouping::table",
        "catalogue/grouping::functions",
        "catalogue/grouping::whole",
        "catalogue/grouping::sort_entries",
        "catalogue/grouping::filter",
        "catalogue/grouping::kind",
        "catalogue/grouping::order",
        "catalogue/grouping::same",
        "catalogue/grouping::canonical",
        "catalogue/grouping::group",
        "catalogue/grouping::call",
        "catalogue/grouping::column",
        "catalogue/grouping::aggregate",
        "catalogue/grouping::text",
        "catalogue/grouping::headers",
        "catalogue/grouping::pairs",
        "catalogue/grouping::function_name",
        "catalogue/grouping::sort_groups",
        "catalogue/grouping::result",
        "decimal::low32",
        "decimal::Natural::from_u64",
        "decimal::Natural::pow10",
        "decimal::Natural::normalize",
        "decimal::Natural::is_zero",
        "decimal::Natural::mul_add_small",
        "decimal::Natural::times_pow10",
        "decimal::Natural::times_pow5",
        "decimal::Natural::times_pow2",
        "decimal::ExactDecimal::binary"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/grouping.rs#L796-L796",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 1,454 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.PIVOTBY.json",
  "name": "PIVOTBY",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n[GROUPBY](FUNC.GROUPBY.md) has only row groups; [PERCENTOF](FUNC.PERCENTOF.md) calculates a share within a supplied comparison set; [SUMIFS](FUNC.SUMIFS.md) can build a fixed cross-tab manually.\n\n\n",
    "how-to-implement": "\nValidate row alignment of both key tables, value columns and filter flags. Resolve header policy, group typed row and column tuples, sort each axis, and invoke the callback on values at each intersection. Generate subtotal/grand-total cells from their source-row sets. For a two-argument callable choose the second set using relative_to, preserving the grouping level. The current source retains separate scope limits for parent totals, multiple value columns and boxed array results; a basic hash-map sum does not implement these branches. The example has one row in each intersection, so it isolates layout from reduction.\n\n\n",
    "quirks": "\nHeader inference and spill space matter. Totals have separate row and column depth controls, including negative depths for totals before details. Relative_to applies only to two-argument callbacks: the public page lists column, row, grand, parent-column and parent-row comparison sets. Empty intersections are not automatically numeric zeros in the current recorded route.\n\n| Optional argument | What it controls |\n|---|---|\n| `field_headers` | Whether the first source row is data or headings, and which headings appear. Modes are shared with GROUPBY. |\n| `row_total_depth`, `col_total_depth` | Independent grand totals and hierarchy subtotals; `0` omits that axis's totals. |\n| `row_sort_order`, `col_sort_order` | Signed sort positions; negative means descending. |\n| `filter_array` | One Boolean for each source record. |\n| `relative_to` | `0` column, `1` row, `2` grand, `3` parent-column, `4` parent-row comparison set. |\n\nThe row and column field arguments both describe source **columns**. They are not already shaped row/column headers to cross-multiply. This formula returns a spill array; it does not create an Excel PivotTable object.\n\n\n",
    "sources": "\n- [Microsoft: PIVOTBY function](https://support.microsoft.com/en-us/excel/functions/pivotby-function), opened 6 November 2026; syntax, documented argument rules and errors.\n- [DnaCalc implementation](https://github.com/DnaCalc/DnaCalc/blob/da3ecc4fb19a3a5529708c311d0e8f05688ac165/crates/calc-func/src/catalogue/grouping.rs); implementation steps and the limits identified in the text.\n\n",
    "try-it": "\nPut regions `east,east,west,west` in B2:B5, periods `Q1,Q2,Q1,Q2` in C2:C5 and amounts `3,7,5,11` in D2:D5. `=PIVOTBY(B2:B5,C2:C5,D2:D5,LAMBDA(v,SUM(v)),0,0,,0)` returns east with Q1=3, Q2=7, and west with Q1=5, Q2=11, without totals.\n\nA two-argument share callback can use the whole table as its denominator:\n\n```excel\n=PIVOTBY(B2:B5,C2:C5,D2:D5,LAMBDA(s,t,SUM(s)/SUM(t)),0,0,,0,,,2)\n```\n\nThe final `2` selects the grand-total comparison set. East/Q1 is `3/26`, about `0.1153846154`. With relative_to zero its column denominator is `3+5=8`, giving `0.375`; with one its row denominator is `3+7=10`, giving `0.3`. Percentage formatting changes their display, not those fractions.\n\n\n",
    "version-differences": "\nThe implementation comments retain Excel 16.0 build 20527 COM readings on 30 October 2026, including fifteen depth controls and ten multi-value/subtotal controls. They identify behaviour on that build and input scope. No same-input earlier-build comparison is recorded here.\n\n\n",
    "what-it-does": "\n`PIVOTBY(row_fields,col_fields,values,function,[field_headers],[row_total_depth],[row_sort_order],[col_total_depth],[col_sort_order],[filter_array],[relative_to])` groups records along row and column keys, applies an aggregation callback and spills the cross-tabulation. Its optional arguments control headers, row/column totals and sorting, filtering, and the comparison set for a two-argument callback.\n\n\n"
  },
  "signature": {
    "display": "PIVOTBY(row_fields, col_fields, values, function, [field_headers], [row_total_depth], [row_sort_order], [col_total_depth], [col_sort_order], [filter_array], [relative_to])",
    "parameters": [
      {
        "description": null,
        "name": "row_fields",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "col_fields",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "values",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "function",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "field_headers",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "row_total_depth",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "row_sort_order",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "col_total_depth",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "col_sort_order",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "filter_array",
        "optional": true,
        "repeats": false
      },
      {
        "description": null,
        "name": "relative_to",
        "optional": true,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 11,
        "min": 4
      },
      "category": "Lookup and reference functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "ReductionFold",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "kernel_signature_class": "Custom",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "A cross-tab of values aggregated by row groups and column groups",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Helps a user group, aggregate, sort, and filter data based on the row and column fields that you specify",
        "microsoft_url": "https://support.microsoft.com/en-us/office/pivotby-function-de86516a-90ad-4ced-8522-3a25fac389cf"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "PIVOTBY"
        },
        {
          "locale": "bg-BG",
          "name": "PIVOTBY"
        },
        {
          "locale": "cs-CZ",
          "name": "KONTPODLE"
        },
        {
          "locale": "da-DK",
          "name": "PIVOTER.EFTER"
        },
        {
          "locale": "de-DE",
          "name": "PIVOTBY"
        },
        {
          "locale": "el-GR",
          "name": "PIVOTBY"
        },
        {
          "locale": "en-AU",
          "name": "PIVOTBY"
        },
        {
          "locale": "en-GB",
          "name": "PIVOTBY"
        },
        {
          "locale": "en-US",
          "name": "PIVOTBY"
        },
        {
          "locale": "es-ES",
          "name": "PIVOTARPOR"
        },
        {
          "locale": "et-EE",
          "name": "PIVOTBY"
        },
        {
          "locale": "fi-FI",
          "name": "PIVOT.ARVOJEN.MUKAAN"
        },
        {
          "locale": "fr-FR",
          "name": "CROISER.AVEC*"
        },
        {
          "locale": "he-IL",
          "name": "PIVOTBY"
        },
        {
          "locale": "hr-HR",
          "name": "PIVOTBY"
        },
        {
          "locale": "hu-HU",
          "name": "KIMUTATÁS.ALAP.SZERINT"
        },
        {
          "locale": "id-ID",
          "name": "PIVOTBY"
        },
        {
          "locale": "it-IT",
          "name": "PIVOTBY"
        },
        {
          "locale": "ja-JP",
          "name": "PIVOTBY"
        },
        {
          "locale": "ko-KR",
          "name": "PIVOTBY"
        },
        {
          "locale": "lt-LT",
          "name": "PIVOTBY"
        },
        {
          "locale": "lv-LV",
          "name": "PIVOTBY"
        },
        {
          "locale": "nb-NO",
          "name": "PIVOTBY"
        },
        {
          "locale": "nl-NL",
          "name": "DRAAIEN.PER"
        },
        {
          "locale": "pl-PL",
          "name": "PRZESTAWIAJ.WEDŁUG"
        },
        {
          "locale": "pt-BR",
          "name": "PIVOTBY"
        },
        {
          "locale": "pt-PT",
          "name": "DINAMIZARPOR"
        },
        {
          "locale": "ro-RO",
          "name": "PIVOTBY"
        },
        {
          "locale": "ru-RU",
          "name": "СВОДПО"
        },
        {
          "locale": "sk-SK",
          "name": "PIVOTBY"
        },
        {
          "locale": "sl-SI",
          "name": "PIVOTBY"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "PIVOTBY"
        },
        {
          "locale": "sv-SE",
          "name": "PIVOTERAEFTER"
        },
        {
          "locale": "th-TH",
          "name": "PIVOTBY"
        },
        {
          "locale": "tr-TR",
          "name": "ÖZETÖLÇÜT"
        },
        {
          "locale": "uk-UA",
          "name": "PIVOTBY"
        },
        {
          "locale": "vi-VN",
          "name": "PIVOTBY"
        },
        {
          "locale": "zh-CN",
          "name": "PIVOTBY"
        },
        {
          "locale": "zh-HK",
          "name": "PIVOTBY"
        },
        {
          "locale": "zh-TW",
          "name": "PIVOTBY"
        }
      ],
      "signature": {
        "display": "PIVOTBY(row_fields, col_fields, values, function, [field_headers], [row_total_depth], [row_sort_order], [col_total_depth], [col_sort_order], [filter_array], [relative_to])",
        "parameters": [
          {
            "description": null,
            "name": "row_fields",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "col_fields",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "values",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "function",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "field_headers",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "row_total_depth",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "row_sort_order",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "col_total_depth",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "col_sort_order",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "filter_array",
            "optional": true,
            "repeats": false
          },
          {
            "description": null,
            "name": "relative_to",
            "optional": true,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "PIVOTBY",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/pivotby-function-de86516a-90ad-4ced-8522-3a25fac389cf"
  },
  "try_it": {
    "formula": "=PIVOTBY(B2:B5,C2:C5,D2:D5,LAMBDA(v,SUM(v)),0,0,,0)",
    "inputs": {
      "B2": "east",
      "B3": "east",
      "B4": "west",
      "B5": "west",
      "C2": "Q1",
      "C3": "Q2",
      "C4": "Q1",
      "C5": "Q2",
      "D2": 3,
      "D3": 7,
      "D4": 5,
      "D5": 11
    }
  },
  "url": "https://handbook.dnacalc.com/functions/PIVOTBY.html",
  "variants": [],
  "versions": [
    {
      "behaviour": "Implementation comments retain 15 depth controls and 10 multi-value/subtotal controls on 30 October 2026. Empty intersections, parent comparison sets and boxed callback arrays retain their separately stated scopes; no cross-build difference is established.",
      "excel_build": "16.0 build 20527",
      "platform": "Windows through COM; bitness and CPU not stated in these comments",
      "sources": [
        "https://github.com/DnaCalc/DnaCalc/blob/da3ecc4fb19a3a5529708c311d0e8f05688ac165/crates/calc-func/src/catalogue/grouping.rs"
      ]
    }
  ]
}