資料透視表

支援 Headless

資料透視表是一種強大的資料分析工具,允許使用者快速彙總、分析和視覺化大量資料。它支援多種資料操作和格式設定選項,幫助使用者更直觀地理解資料。

簡介

資料透視表通常用於以下場景:

  • 彙總資料:資料透視表可以幫助你快速彙總資料,以便更好地瞭解資料的整體情況。
  • 分析資料:資料透視表可以幫助你分析資料,找出資料中的模式和關係。
  • 探索資料:資料透視表可以幫助你探索資料,發現資料中的規律和趨勢。
  • 視覺化資料:資料透視表可以幫助你將資料視覺化,以便更好地理解資料。

資料透視表通常包含以下幾個要素:

  • 行標籤:資料透視表中的行標籤用於對資料進行分組。
  • 列標籤:資料透視表中的列標籤用於對資料進行分組。
  • 值:資料透視表中的值用於對資料進行彙總。

在資料透視表中,你可以根據需要對行標籤、列標籤和值進行調整,以便更好地分析資料。

資料來源

在 Univer Sheets 中,資料透視表的資料來源可以是一個工作表(Worksheet),也可以是一個資料區域。你可以根據需要選擇不同的資料來源,以便更好地分析資料。 我們會以資料來源的第一行作為預設的列標籤,其他部分作為資料來源。因此我們要求資料來源儘可能的歸整,儘可能避免空行,空列。 在同一列的資料中,我們會自動識別資料型別,以便更好的支援資料透視表的功能。假設在某一列中,資料型別不一致,我們會預設將該列的資料型別設定為字串。

在 Univer Sheets 中,資料透視表會自動響應資料的變化,當資料來源發生變化時,資料透視表會自動更新,以便更好地分析資料。

篩選

資料透視表支援對行標籤和列標籤進行篩選,同時提供篩選欄位,該欄位不會參與資料透視表主要資料分類彙總部分的排版,但是可以用於篩選資料。

資料透視表支援兩種篩選方式:

  • 標籤篩選:標籤篩選是直接作用於當前標籤的維度的項(item), 例如在省份維度下,我們可以過濾掉部分省份。
  • 值篩選:值篩選需要指定一個值維度,然後會對值欄位的彙總結果進行篩選,例如我們可以過濾掉銷售額小於 1000 的資料。

排序

資料透視表的排序只會在行/列欄位生效,排序方式支援升序和降序,排序方式使用 localCompare 方式。後續我們會支援更多的排序方式,例如拼音排序。

資料透視表的排序支援兩種方式:

  • 標籤排序:標籤排序是直接作用於當前標籤的維度的項(item), 例如在省份維度下,我們可以按照省份名稱排序。
  • 值排序:值排序需要指定一個值維度,然後會對值欄位的彙總結果進行排序,例如我們可以按照銷售額排序。

彙總

資料透視表支援 11 種 excel 支援的彙總方式,包括:求和、計數、資料計數、平均值、最大值、最小值、階乘、標準差、方差、總體標準差、總體方差。

資料透視表支援多個值維度,同時可以客製化多值維度所在區域(value position)和位置(value index)。

這是很複雜的排版邏輯, 因此我們僅支援了表格檢視,後續我們會根據情況支援更多的檢視。

下鑽

下鑽是指在資料透視表的值區域中,使用者可以透過雙擊某個單元格,檢視該單元格對應的詳細資料。例如,使用者可以在資料透視表中點選某個單元格,檢視該單元格的詳細資料,以便更好地追溯原資料。

分組

Univer Sheets 支援日期、數字和手動分組。

  • 日期分組:透過 setDateGroupType 設定衍生日期欄位的分組類型。若要按日曆單位對原始日期標籤欄位分組,先透過 setDateGroupingMode 設定 univerAPI.Enum.PivotDateGroupingMode.ExcelLike,再呼叫 setExcelDateGroup。
  • 數字分組:向 setNumberGroup 傳入標籤欄位 ID 和區間設定。
  • 手動分組:向 setManualGroups 傳入原始來源欄位 ID 和保留值類型的成員分組。每組至少包含兩個成員;傳入空陣列可移除該欄位的全部手動分組。

使用交叉分析篩選器和時間軸可以互動式篩選表格和樞紐報表。

外掛模式

安裝

Shell
pnpm add @univerjs-pro/sheets-pivot @univerjs-pro/sheets-pivot-ui

使用

TypeScript
import { UniverSheetsPivotTablePlugin } from '@univerjs-pro/sheets-pivot'import { UniverSheetsPivotTableUIPlugin } from '@univerjs-pro/sheets-pivot-ui'import SheetsPivotTableUIZhTW from '@univerjs-pro/sheets-pivot-ui/locale/zh-TW'import SheetsPivotTableZhTW from '@univerjs-pro/sheets-pivot/locale/zh-TW'import { LocaleType, mergeLocales, Univer } from '@univerjs/core'import '@univerjs-pro/sheets-pivot-ui/lib/index.css'import '@univerjs-pro/sheets-pivot/facade'const univer = new Univer({  locale: LocaleType.ZH_TW,  locales: {    [LocaleType.ZH_TW]: mergeLocales(      SheetsPivotTableZhTW,       SheetsPivotTableUIZhTW,     ),  },})

外掛註冊

透視表外掛支援針對不同的使用場景靈活註冊,提供兩種模式以適配不同的計算需求。

單獨註冊在主程序

透視表外掛可以單獨在主程序中註冊。這種模式適用於輕量級任務,操作簡單,無需額外配置外掛 config。開發者只需引入 UniverSheetsPivotTablePlugin 即可。

TypeScript
univer.registerPlugin(UniverSheetsPivotTablePlugin)univer.registerPlugin(UniverSheetsPivotTableUIPlugin)

主程序和 worker 程序同時註冊

對於需要高效能的場景,透視表外掛支援同時註冊在主程序和 worker 程序中。透過這種模式,外掛可以利用多執行緒架構實現高效的資料分發和計算處理,顯著減輕主程序的計算負擔,並提升整體效能。

在這種模式下,主程序主要負責資料的分發、同步和渲染,worker 程序專注於複雜的計算任務。為實現這一模式,需要在註冊時透過 config 進行精細化配置。

TypeScript
// 瀏覽器主程序外掛註冊檔案// notExecuteFormula 為 true 表示主程序不執行計算,只負責資料的分發、同步和渲染univer.registerPlugin(UniverSheetsPivotTablePlugin, { notExecuteFormula: true })univer.registerPlugin(UniverSheetsPivotTableUIPlugin)// web worker 程序外掛註冊檔案// notExecuteFormula 為 false 表示 worker 程序執行計算univer.registerPlugin(UniverSheetsPivotTablePlugin, { notExecuteFormula: false })

如果你擁有 Univer 的商業許可證,請參考在客戶端使用許可證進行配置。

外掛與配置

TypeScript
import type { DateSystem } from '@univerjs/core'interface IUniverSheetsPivotConfig {  /**   * 定義資料透視表中每個字段可顯示的最大項目數。   * @default 1000   */  maxLimitItemCount?: number  /**   * 將日期欄位新增至列或欄時,自動建立日期群組。   * @default true   */  autoDateGroup?: boolean  /**   * 日期群組使用的日期系統。   * @default DateSystem.Date1900   */  dateSystem?: DateSystem}

行動裝置支援

先設定行動版編輯器。在本頁外掛模式的初始化程式碼中,將下列桌面版註冊替換為同一套件匯出的行動版外掛,並在開啟文件前完成。保留模型外掛、樣式、語言套件與 Facade 匯入,請勿同時註冊兩個版本。

套件桌面版註冊行動版註冊
@univerjs-pro/sheets-pivot-uiUniverSheetsPivotTableUIPluginUniverSheetsPivotTableMobileUIPlugin

預設模式

列印功能被包含在 @univerjs/preset-sheets-advanced 預設中。

安裝

@univerjs/preset-sheets-advanced 的 UniverSheetsAdvancedPreset 預設在執行時依賴 UniverSheetsDrawingPreset 預設,請先安裝 @univerjs/preset-sheets-drawing。

Shell
pnpm add @univerjs/preset-sheets-drawing @univerjs/preset-sheets-advanced

使用

TypeScript
import { UniverSheetsAdvancedPreset } from '@univerjs/preset-sheets-advanced'import UniverPresetSheetsAdvancedZhTW from '@univerjs/preset-sheets-advanced/locales/zh-TW'import { UniverSheetsCorePreset } from '@univerjs/preset-sheets-core'import UniverPresetSheetsCoreZhTW from '@univerjs/preset-sheets-core/locales/zh-TW'import { UniverSheetsDrawingPreset } from '@univerjs/preset-sheets-drawing'import UniverPresetSheetsDrawingZhTW from '@univerjs/preset-sheets-drawing/locales/zh-TW'import { createUniver, LocaleType, mergeLocales } from '@univerjs/presets'import '@univerjs/preset-sheets-core/lib/index.css'import '@univerjs/preset-sheets-drawing/lib/index.css'import '@univerjs/preset-sheets-advanced/lib/index.css'const { univerAPI } = createUniver({  locale: LocaleType.ZH_TW,  locales: {    [LocaleType.ZH_TW]: mergeLocales(      UniverPresetSheetsCoreZhTW,      UniverPresetSheetsDrawingZhTW,       UniverPresetSheetsAdvancedZhTW,     ),  },  presets: [    UniverSheetsCorePreset(),    UniverSheetsDrawingPreset(),     UniverSheetsAdvancedPreset(),   ],})

如果你擁有 Univer 的商業許可證,請參考在客戶端使用許可證進行配置。

預設與配置

TypeScript
interface IUniverSheetsAdvancedPresetConfig {  pivot?: Pick<IUniverSheetsPivotConfig, 'maxLimitItemCount'>}interface IUniverSheetsPivotConfig {  /**   * 定義資料透視表中每個字段可顯示的最大項目數。   * @default 1000   */  maxLimitItemCount?: number}

Facade API

完整 Facade API 型別定義,請檢視 FacadeAPI。

引入

外掛模式提示

僅外掛模式需要手動引入 Facade 套件。預設模式已內建對應的 Facade 套件,無需額外引入。

TypeScript
import '@univerjs-pro/sheets-pivot/facade'

新增透視表

FWorkbook.addPivotTable 方法用於新增透視表,成功會返回 FPivotTable 例項。

TypeScript
// 需要確保工作表範圍 A1:G9 是非空的const fWorkbook = univerAPI.getActiveWorkbook()const unitId = fWorkbook.getId()const fSheet = fWorkbook.getActiveSheet()const subUnitId = fSheet.getSheetId()const sheetName = fSheet.getSheetName()const sourceInfo = {  unitId,  subUnitId,  sheetName,  range: {    startRow: 0,    startColumn: 0,    endRow: 8,    endColumn: 6,  },}const anchorCellInfo = {  unitId,  subUnitId,  row: 20,  col: 8,}const fPivotTable = await fWorkbook.addPivotTable(sourceInfo, univerAPI.Enum.PositionTypeEnum.Existing, anchorCellInfo)const pivotTableId = fPivotTable.getPivotTableId()// 設定狀態,避免重複新增維度let hasAdded = false// 透視表的建立是非同步的,因此需要等待透視表渲染完成後再新增維度univerAPI.addEvent(univerAPI.Event.PivotTableRendered, async (params) => {  if (!hasAdded && params.pivotTableId === pivotTableId) {    hasAdded = true    await fPivotTable.addField(1, univerAPI.Enum.PivotTableFiledAreaEnum.Row, 0)    await fPivotTable.addField(1, univerAPI.Enum.PivotTableFiledAreaEnum.Value, 0)  }})

獲取透視表

FWorkbook.getPivotTableByCell 方法透過錨定單元格獲取透視表例項。如果目標單元格在透視表中,它將返回 FPivotTable 例項。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const unitId = fWorkbook.getId()const fSheet = fWorkbook.getActiveSheet()const subUnitId = fSheet.getSheetId()// 從 FWorkbook 中獲取透視表例項const fPivotTable = fWorkbook.getPivotTableByCell(unitId, subUnitId, 0, 8)// 從 FSheet 中獲取透視表例項const pivotTable2 = fSheet.getPivotTableByCell(0, 8)

FPivotTable 例項中有一些方法,可以用來操作透視表。

方法描述
remove刪除透視表例項
getConfig獲取當前透視表的配置資訊,其中包括資料來源範圍,錨定單元格, 維度配置資訊
addField新增一個維度
removeField刪除一個維度
updateFieldPosition更新維度的所在區域以及順序
updateValuePosition更新 ∑Value 的位置
setSubtotalType設定彙總方式
setLabelSort設定標籤排序
setLabelManualFilter設定標籤篩選
renameField重新命名維度
setValueFilter設定值維度
reset重置透視表的維度配置
setFieldsConfig設定透視表的維度配置
getValueFilters獲取透視表的值維度配置

事件監聽

完整事件型別定義,請檢視 Events。

univerAPI.Event.BeforePivotTableAdd 事件在新增透視表之前觸發。

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforePivotTableAdd, (params) => {  const { positionType, targetCellInfo } = params  if (positionType === univerAPI.Enum.PositionTypeEnum.Existing && targetCellInfo.sheetName === 'Sheet 1') {    // 取消新增透視表操作    params.cancel = true    console.log(`無法將透視表新增到 ${targetCellInfo.sheetName} 工作表`)  }})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableAdded 事件在新增透視表之後觸發。

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableAdded, (params) => {  const { positionType, targetCellInfo } = params  if (positionType === univerAPI.Enum.PositionTypeEnum.Existing) {    console.log('在現有工作表中建立了一個透視表')    console.log(`      目標工作表名稱為 ${targetCellInfo.sheetName},      目標行為 ${targetCellInfo.row}, 目標列為 ${targetCellInfo.column}    `)  } else {    console.log('在新工作表中建立了一個透視表')  }})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.BeforePivotTableMove 事件在移動透視表之前觸發。

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforePivotTableMove, (params) => {  const { pivotTableId, targetCellInfo } = params  if (pivotTableId === 'pivotTable1' && targetCellInfo.sheetName === 'Sheet 1') {    // 取消移動透視表操作    params.cancel = true    console.log(`無法將透視表移動到 ${targetCellInfo.sheetName} 工作表`)  }})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableMoved 事件在移動透視表之後觸發。

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableMoved, (params) => {  const { pivotTableId, targetCellInfo, originTargetInfo } = params  if (pivotTableId === 'pivotTable1') {    console.log(`      透視表從行: ${originTargetInfo.row} & 列: ${originTargetInfo.column}      移動到工作表 ${targetCellInfo.sheetName} 行: ${targetCellInfo.row} & 列: ${targetCellInfo.column}    `)  }})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableRendered 事件在透視表渲染完成後觸發。

TypeScript
// import { unionPivotViewRange } from '@univerjs-pro/sheets-pivot';const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableRendered, (params) => {  const { pivotTableId, rangeInfo } = params  console.log(`透視表 ${pivotTableId} 已渲染`)  if (rangeInfo) {    console.log(unionPivotViewRange(rangeInfo))  }})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableRemoved 事件在透視表被刪除後觸發。

TypeScript
const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableRemoved, (params) => {  const { pivotTableId } = params  console.log(`透視表 ${pivotTableId} 已被刪除`)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableFieldAdded 事件在透視表新增維度後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableFieldAdded, (params) => {  const { pivotTableId, fieldId, fieldArea, fieldIndex } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const fieldSetting = pivotTable.getFieldSetting(fieldId)  console.log(fieldSetting)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableFieldRemoved 事件在透視表刪除維度後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableFieldRemoved, (params) => {  const { pivotTableId, fieldId } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const fieldSetting = pivotTable.getFieldSetting(fieldId)  console.log(fieldSetting)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableFieldMoved 事件在透視表移動維度後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableFieldMoved, (params) => {  const { pivotTableId, fieldId, fieldArea, fieldIndex } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const fieldSetting = pivotTable.getFieldSetting(fieldId)  console.log(`源名稱 ${fieldSetting.sourceName} 顯示名稱 ${fieldSetting.displayName}`)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableFieldCollapseChanged 事件在透視表展開/摺疊維度後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableFieldCollapseChanged, (params) => {  const { pivotTableId, fieldId, isCollapsed } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const fieldSetting = pivotTable.getFieldSetting(fieldId)  console.log(`源名稱 ${fieldSetting.sourceName} 顯示名稱 ${fieldSetting.displayName}`)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableFieldFilterChanged 事件在透視表維度篩選後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableFieldFilterChanged, (params) => {  const { pivotTableId, fieldId, filter } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const fieldSetting = pivotTable.getFieldSetting(fieldId)  console.log(`檢查列表篩選值為 ${fieldSetting.filterInfo.checklist}`)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableFieldSortChanged 事件在透視表維度排序後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableFieldSortChanged, (params) => {  const { pivotTableId, fieldId, sort } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const fieldSetting = pivotTable.getFieldSetting(fieldId)  console.log(`排序資訊為 ${fieldSetting.sortInfo}`)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableFieldSettingChanged 事件在透視表維度設定變更後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableFieldSettingChanged, (params) => {  const { pivotTableId, fieldId, setting } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const fieldSetting = pivotTable.getFieldSetting(fieldId)  console.log(`源名稱 ${fieldSetting.sourceName} 顯示名稱 ${fieldSetting.displayName}`)})// 移除事件監聽器,使用 `disposable.dispose()`

univerAPI.Event.PivotTableValuePositionChanged 事件在透視表值位置變更後觸發。

TypeScript
const fWorkbook = univerAPI.getActiveWorkbook()const disposable = univerAPI.addEvent(univerAPI.Event.PivotTableValuePositionChanged, (params) => {  const { pivotTableId, valueId, position } = params  const pivotTable = fWorkbook.getPivotTableById(pivotTableId)  const valueSetting = pivotTable.getValueSetting(valueId)  console.log(`源名稱 ${valueSetting.sourceName} 顯示名稱 ${valueSetting.displayName}`)})// 移除事件監聽器,使用 `disposable.dispose()`

值顯示方式

使用 setShowDataAs() 將值欄位顯示為列、欄或總計的百分比,也可顯示相對於基準項目的差異。這只改變顯示計算,不會取代來源資料。getShowDataAs() 讀取設定,resetShowDataAs() 還原一般計算。

TypeScript
const valueId = fPivotTable.getFieldIdsByArea(  univerAPI.Enum.PivotTableFiledAreaEnum.Value,)[0]if (valueId) {  await fPivotTable.setShowDataAs(valueId, {    type: univerAPI.Enum.PivotShowAsTypeEnum.percentOfGrandTotal,  })  console.log(fPivotTable.getShowDataAs(valueId))}

範例中的 fPivotTable 是既有樞紐分析表。請使用值欄位 ID,而非來源欄或列欄位 ID。差異與累計等模式還需要設定對應的基準欄位與基準項目。

隨工作表複製樞紐分析表

註冊樞紐分析表外掛後,複製工作表也會複製表上的樞紐分析表並保留欄位設定。每個副本會取得新的樞紐分析表 ID。若資料來源位於被複製的工作表,參照會改為指向新工作表;若來源位於其他工作表或活頁簿,則保留原參照。樞紐分析表副本會隨工作表複製操作一起復原和重做。

TypeScript
const workbook = univerAPI.getActiveWorkbook()if (!workbook) throw new Error('No active workbook')const copiedSheet = workbook.duplicateActiveSheet()console.log(copiedSheet.getSheetName())

多重篩選與日期條件

setOptions({ allowMultipleFilters: true }) 允許同一欄位同時使用成員選取、標籤/日期條件和值篩選。省略或設為 false 時,不同類別的篩選互相取代;關閉選項時若存在類別衝突,會清除報表篩選。同一欄位仍最多只能有一個值篩選。

setDateFilter() 支援 dateEqual、dateOlderThan、dateBetween 等固定日期條件。expected 使用活頁簿日期系統中的 Excel 序列值,區間條件傳入兩個值。useWholeDay: true 忽略一天內的時間;省略或設為 false 時按精確序列值比較。參數使用報表欄位 ID,而非來源欄索引。以下沿用前文的 fPivotTable,並要求資料來源包含 Date 欄。

getDateFilter() 回傳獨立的條件副本,clearDateFilter() 僅清除日期條件。操作支援復原及協作。請檢查回傳的布林值:已生效的交叉分析篩選器可能阻止不相容的篩選條件。

TypeScript
if (!fPivotTable) throw new Error('PivotTable not found')await fPivotTable.setOptions({ allowMultipleFilters: true })const dateField = Object.values(fPivotTable.getConfig()?.fieldsConfig.dimension ?? {})  .find((field) => field.sourceName === 'Date')if (!dateField) throw new Error('Add the Date field to the report first')await fPivotTable.setDateFilter(dateField.id, {  operator: univerAPI.Enum.ST_PivotFilterOperatorEnum.dateEqual,  expected: 45293,  useWholeDay: true,})console.log(fPivotTable.getDateFilter(dateField.id))await fPivotTable.clearDateFilter(dateField.id)

GETPIVOTDATA

使用 =GETPIVOTDATA("Sales",$I$1,"Region","East"),從左上角位於 I1 的可見樞紐分析表報表讀取彙總值。值欄位可使用顯示名稱或來源欄位名稱。錨點必須是單一儲存格參照,欄位/項目參數必須成對提供。

目前實作從錨點最多向下掃描 200 列、向右掃描 50 欄可見報表,不查詢隱藏的來源記錄。找不到欄位、項目或結果時回傳 #REF!;參數數量不合法或錨點不是單一儲存格參照時回傳 #VALUE!。

你覺得這篇文檔如何?

© 2026 DreamNum Co., Ltd.