A pivot table summarises a range, or an Excel table, written earlier in the same workbook. SheetStream writes the pivot's layout and asks Excel to compute it when the file opens, so the result is a real, interactive pivot: users can drag fields, filter, drill and refresh exactly as if they had built it themselves.
using SheetStream;
using var package = ExcelPackage.Create("sales.xlsx");
var wb = package.Workbook;
var data = wb.Worksheets.Add("Data");
var loaded = data.LoadFromCollection(orders, new LoadOptions { TableName = "Orders" });
var report = wb.Worksheets.Add("Pivot");
var pivot = report.AddPivotTable("SalesByRegion", loaded.Table!, row: 3, column: 1);
pivot.AddRowField("Region");
pivot.AddColumnField("Category");
pivot.AddDataField("Amount", PivotFunction.Sum, numberFormat: "$#,##0.00");
pivot.AddDataField("OrderId", PivotFunction.Count, displayName: "Orders");
package.Save();| Overload | Source | Field names come from |
|---|---|---|
AddPivotTable(name, excelTable, row, column) |
An ExcelTable from AddTable or LoadOptions.TableName (LoadResult.Table) |
The table's columns. Excel re-reads the whole table on each refresh, so the pivot follows the table when rows are added later in Excel. |
AddPivotTable(name, sourceSheetName, sourceRange, row, column, headers) |
Any A1 range including its header row, e.g. "A1:F500" |
The headers you pass. LoadResult.Headers and LoadResult.Range give you both for data written with a LoadFrom* call. |
The header texts are needed because the source sheet has already been streamed into the file: SheetStream cannot read it back. Field names are matched case-insensitively; an unknown name throws an ArgumentException that lists the available headers.
The source sheet may be the pivot's own sheet (a pivot next to its data) or any sheet added earlier. It must exist in the workbook when AddPivotTable is called.
| Method | Excel area | Notes |
|---|---|---|
AddRowField(header) |
Rows | Several row fields nest in the order they are added. |
AddColumnField(header) |
Columns | |
AddFilterField(header) |
Filters (report filter / page field) | Each filter takes one row above the pivot body, followed by one blank row, as Excel lays it out. row is the first filter cell. |
AddDataField(header, function, displayName, numberFormat) |
Values | PivotFunction: Sum (default), Count, Average, Max, Min, Product, CountNumbers, StdDev, StdDevP, Var, VarP. The default caption is "Sum of Amount" style. With more than one data field Excel shows them side by side under a "Values" header. |
A data field's caption must differ from every source header. Excel itself refuses displayName: "Amount" when a column is called Amount ("PivotTable field name already exists"), so SheetStream rejects it up front.
Options on PivotTable:
StyleName: a built-in pivot style, default"PivotStyleMedium9"; alsoShowRowStripes/ShowColumnStripes.ShowRowGrandTotals(the Grand Total column at the right) andShowColumnGrandTotals(the Grand Total row at the bottom), both defaulttrue.Compact:true(default) stacks all row fields in one indented column, as Excel creates pivots;falsegives outline form with one column per row field.
Several pivots can share a sheet, sit on different sheets or point at the same source; each gets its own cache. Pivot names must be unique within the workbook.
Streaming means the data is gone by the time the pivot is written, so SheetStream does not build the pivot cache (the list of distinct items per field and the record table) that Excel normally stores next to a pivot. Instead the file carries:
xl/pivotCache/pivotCacheDefinitionN.xmlwith the source reference, onecacheFieldper header, no items,recordCount="0",saveData="0"andrefreshOnLoad="1";xl/pivotCache/pivotCacheRecordsN.xmlwith zero records (Excel expects the part to exist even when it is empty);xl/pivotTables/pivotTableN.xmlwith the fields, their areas, the style and alocationsized for one item per axis.
refreshOnLoad makes Excel read the source cells and compute every total the moment the workbook opens, exactly as if the user had clicked Refresh All, and it then lays the pivot out for the real number of items. Opening and saving the file in Excel stores a full cache like any other pivot.
Version stamps are written as Excel 2016 writes them (createdVersion/refreshedVersion 6, minRefreshableVersion 3): Excel treats a cache whose refreshed version is older than the pivot's as stale and some builds then refuse to refresh it.
tests/excel-check-pivot.ps1 opens a workbook through Excel COM automation, checks that no part was dropped by a repair, calls RefreshTable() on every pivot and prints the refreshed cells; it is how the shipped pivots were verified.
- No cached data. A viewer that does not run the pivot engine (web previews, some mobile apps, older LibreOffice builds) shows the header cells only, until the file has been opened and saved in Excel. If the report must render everywhere, write the summary as plain cells (
GroupByplusWriteCell) or formulas (SUMIFSon the table) instead. - Supported layouts: row, column and filter fields, data fields with the eleven standard functions, number formats, grand totals, compact or outline form, built-in styles.
- Not supported: calculated fields and items, grouping (dates, numbers), slicers and timelines, custom sort orders, "show values as" (percent of total, running total), conditional formats inside the pivot, OLAP sources, external connections.
- Pivots cannot be added to template or edited workbooks (
OpenTemplate,Edit), and existing pivots are not read or modified. - A pivot whose source range has only a header row is refused (
ArgumentException), as Excel cannot build a cache from it.