Pivot tablo API'si
HotXLS; XLS ve XLSX çalışma kitapları için türlü pivot tablo incelemeyi, pivot tablo oluşturmayı ve sonuçları somutlaştırmayı destekler. İlişki tabanlı XLSX yükleme, paket parça adlarını serbestçe çözümler ve önbellek kayıtlarını, paylaşılan öğeleri, alan üst verisini, filtreleri, gruplamayı, hesaplanan tanımları, biçimleri ve uzantıları genel modele aktarır. Klasik XLS girdisinde özgün pivot kayıtları saklanır; böylece kaydetme işleminde birebir round-trip yapılır
Round-trip ve türlü model
Klasik bir çalışma kitabı zaten pivot tablolar içeriyorsa okuyucu ham BIFF kayıtlarını korur ve buna ek olarak türlü bir model de sunar. Klasik bir dosyadan yüklenen tablolar ve önbellekler FromRawBlobs = True değerini taşır; böylece kaydetme çıktısı, sadakat için özgün baytları aynen geri yazar. XLSX pivotları, ait oldukları paket ilişkileri üzerinden yüklenir ve kaydedilir; programatik olarak oluşturulan pivotlar ise türlü yazıcıyı kullanır
const
xlPivotBaseItemPrevious = $7FFB;
xlPivotBaseItemNext = $7FFC;
type
TXLSPivotFieldAxis = (xlpfaNone, xlpfaRowField, xlpfaColumnField, xlpfaPageField, xlpfaDataField);
TXLSPivotAggregation = (xlpaSum, xlpaCount, xlpaAverage, xlpaMax, xlpaMin, xlpaProduct, xlpaCountNums, xlpaStdDev, xlpaStdDevP, xlpaVar, xlpaVarP);
TXLSPivotShowDataAs = (xlpsdaNormal, xlpsdaDifference, xlpsdaPercent, xlpsdaPercentDiff, xlpsdaRunTotal, xlpsdaPercentOfRow, xlpsdaPercentOfCol, xlpsdaPercentOfTotal, xlpsdaIndex);
TXLSPivotExtendedShowDataAs = (xlpesdaNone, xlpesdaPercentOfParent, xlpesdaPercentOfParentRow, xlpesdaPercentOfParentColumn, xlpesdaPercentOfRunningTotal, xlpesdaRankAscending, xlpesdaRankDescending);
TXLSPivotSubtotal = (xlpsDefault, xlpsSum, xlpsCount, xlpsAverage, xlpsMax, xlpsMin, xlpsProduct, xlpsCountNums, xlpsStdDev, xlpsStdDevP, xlpsVar, xlpsVarP);
TXLSPivotSubtotals = set of TXLSPivotSubtotal;
TXLSPivotDesignerZone = (xlpdzAvailable, xlpdzRows, xlpdzColumns, xlpdzFilters, xlpdzValues);
TXLSPivotCacheValue = record
ValueType: TXLSPivotCacheFieldType;
end;
TXLSPivotCacheField = class
property Name: WideString;
property FieldType: TXLSPivotCacheFieldType;
property ItemCount: Integer;
property Items[Index: Integer]: TXLSPivotCacheItem;
end;
TXLSPivotCache = class
property CacheId: Integer;
property SourceRangeSheet: WideString;
property SourceFirstRow: Integer;
property SourceFirstCol: Integer;
property SourceLastRow: Integer;
property SourceLastCol: Integer;
property RecordCount: Integer;
property FieldCount: Integer;
property Fields[Index: Integer]: TXLSPivotCacheField;
property RecordIndices[RecordIdx, FieldIdx: Integer]: Integer;
property FromRawBlobs: Boolean;
end;
TXLSPivotCaches = class
function Add: TXLSPivotCache;
function FindByCacheId(ACacheId: Integer): TXLSPivotCache;
property Count: Integer;
property Items[Index: Integer]: TXLSPivotCache;
end;
TXLSPivotField = class
function AddItem: TXLSPivotItem;
function AddCalculatedItem(const AName, AFormula: WideString): TXLSPivotCalculatedItem;
property Name: WideString;
property Axis: TXLSPivotFieldAxis;
property CacheFieldIndex: Integer;
property ItemCount: Integer;
property Items[Index: Integer]: TXLSPivotItem;
property SubtotalMask: Word;
property Subtotals: TXLSPivotSubtotals;
property PageItemIndex: Integer;
property SortType: TXLSPivotFieldSortType;
property SortDataField: Integer;
property Filters: TXLSPivotFilters;
end;
TXLSPivotDataField = class
property Field: TXLSPivotField;
property Aggregation: TXLSPivotAggregation;
property NumberFormat: Word;
property DisplayName: WideString;
property ShowDataAs: TXLSPivotShowDataAs;
property ExtendedShowDataAs: TXLSPivotExtendedShowDataAs;
property BaseField: Integer;
property BaseItem: Integer;
end;
TXLSPivotSupplementalRecord = class
property RecID: Word;
property BodyLength: Integer;
property Body[Index: Integer]: Byte;
end;
TXLSPivotTable = class
function AddField(const AName: WideString; ACacheFieldIndex: Integer): TXLSPivotField;
function FindFieldByName(const AName: WideString): TXLSPivotField;
function SetFieldAxis(const AName: WideString; AAxis: TXLSPivotFieldAxis): TXLSPivotField;
function AddRowField(const AName: WideString): TXLSPivotField;
function AddColumnField(const AName: WideString): TXLSPivotField;
function AddPageField(const AName: WideString): TXLSPivotField;
function AddDataField(AField: TXLSPivotField; AAggregation: TXLSPivotAggregation): TXLSPivotDataField;
function AddDataFieldByName(const AName: WideString; AAggregation: TXLSPivotAggregation = xlpaSum): TXLSPivotDataField;
function AddCalculatedMember(const AName, AFormula: WideString): TXLSPivotCalculatedMember;
function AddSupplementalRecord(ARecID: Word; const ABody: TBytes): TXLSPivotSupplementalRecord;
function Make(AWriter: TlxPivotResultWriter): Integer;
property Name: WideString;
property DataCaption: WideString;
property CacheId: Integer;
property Cache: TXLSPivotCache;
property FieldCount: Integer;
property Fields[Index: Integer]: TXLSPivotField;
property DataFieldCount: Integer;
property DataFields[Index: Integer]: TXLSPivotDataField;
property RowGrandTotals: Boolean;
property ColumnGrandTotals: Boolean;
property MaterializeGrandTotalRow: Boolean;
property MaterializeGrandTotalColumn: Boolean;
property SupplementalRecordCount: Integer;
property SupplementalRecords[Index: Integer]: TXLSPivotSupplementalRecord;
property FromRawBlobs: Boolean;
end;
TXLSPivotDesigner = class
constructor Create(APivotTable: TXLSPivotTable = nil);
procedure ClearLayout;
function MoveField(const AName: WideString; AZone: TXLSPivotDesignerZone; APosition: Integer = -1): Boolean;
function SetAggregation(const AName: WideString; AAggregation: TXLSPivotAggregation): Boolean;
function Validate(out ErrorText: WideString): Boolean;
function Apply(AWriter: TlxPivotResultWriter): Integer;
property PivotTable: TXLSPivotTable;
property FieldCount: Integer;
property Fields[Index: Integer]: TXLSPivotDesignerField;
end;
TXLSPivotTables = class
function Add: TXLSPivotTable;
function FindByName(const AName: WideString): TXLSPivotTable;
property Count: Integer;
property Items[Index: Integer]: TXLSPivotTable;
end;
Çalışma sayfası ve çalışma kitabı giriş noktaları
type
TXLSWorksheet = class
function AddPivotTable(const SourceRangeA1: WideString; DestRow, DestCol: Integer; const Name: WideString): TXLSPivotTable;
function PivotSetDataFieldFormat(DataField: TXLSPivotDataField; const FormatStr: WideString): Word;
property PivotTables: TXLSPivotTables;
end;
TXLSWorkbook = class
property PivotCaches: TXLSPivotCaches;
function RegisterNumFormat(const FormatStr: WideString): Word;
end;
RegisterNumFormat bir sayı biçimi dizesini kaydeder ve BIFF8 ifmt indeksini döndürür; TXLSPivotDataField.NumberFormat ve TXLSPivotCacheField.NumberFormat tam olarak bu indeksi bekler. Aynı dize ikinci kez kaydedilirse aynı indeks döner
DestRow ve DestCol 1 tabanlıdır, tıpkı Cells[Row, Col] gibi; dolayısıyla AddPivotTable('Data!A1:C9', 3, 1, 'SalesPivot') çağrısı pivot tabloyu A3'e çapar. TXLSPivotTable üzerindeki konumlar (FirstRow .. FirstDataCol) ve TXLSPivotCache üzerindeki kaynak aralık da 1 tabanlıdır, aynen XLSX motorundaki gibi; 65,536 x 256'lık sayfanın dışına düşen bir çapa nil döndürür
Sürükle-bırak pivot düzeni kurma
TXLSPivotDesigner, görsel olmayan bir düzen modelidir; pivot mantığını tek bir UI araç takımına bağmadan VCL, FMX, web ya da komut satırı alan listesi arayüzlerinin arkasında çalışabilir
Her alan, kullanılabilir, satır, sütun, filtre veya değer bölgesinden hangisine düştüğünü ve konumunu belirli bir sırayla bildirir; MoveField bir bırakma işlemini uygular, SetAggregation bir değer alanını değiştirir, Validate eksik düzenleri raporlar, Apply ise doğrular ve sonucu normal pivot yazıcısı üzerinden somutlaştırır
Yeni sayısal ve tarih değer alanları xlpaSum ile başlar; metin, Boolean, hata, boş ve karma alanlar ise xlpaCount ile başlar
var
Designer: TXLSPivotDesigner;
ErrorText: WideString;
begin
Designer := TXLSPivotDesigner.Create(Pivot);
try
Designer.MoveField('Region', xlpdzRows);
Designer.MoveField('Quarter', xlpdzColumns);
Designer.MoveField('Closed', xlpdzFilters);
Designer.MoveField('Revenue', xlpdzValues);
Designer.SetAggregation('Revenue', xlpaAverage);
if Designer.Validate(ErrorText) then
Designer.Apply(ResultWriter.WriteCell);
finally
Designer.Free;
end;
end;
Pivot tablo oluşturma
uses lxHandle;
var
Workbook: TXLSWorkbook;
SourceSheet, PivotSheet: TXLSWorksheet;
Pivot: TXLSPivotTable;
RowField: TXLSPivotField;
DataField: TXLSPivotDataField;
begin
Workbook := TXLSWorkbook.Create;
try
SourceSheet := Workbook.Sheets[1];
SourceSheet.Name := 'SalesData';
SourceSheet.Cells[1, 1].Value := 'Region';
SourceSheet.Cells[1, 2].Value := 'Product';
SourceSheet.Cells[1, 3].Value := 'Revenue';
PivotSheet := Workbook.Sheets.Add;
PivotSheet.Name := 'PivotReport';
Pivot := PivotSheet.AddPivotTable('SalesData!A1:C20', 4, 1, 'SalesPivot');
RowField := Pivot.AddRowField('Region');
Pivot.AddColumnField('Product');
DataField := Pivot.AddDataFieldByName('Revenue', xlpaSum);
RowField.Subtotals := [xlpsSum];
PivotSheet.PivotSetDataFieldFormat(DataField, '$#,##0.00');
Workbook.SaveAs('pivot-report.xls');
finally
Workbook.Free;
end;
end;
Değerleri farklı gösterme
Make çağrısından ya da çalışma kitabını kaydetmeden önce her veri alanında ShowDataAs değerini ayarlayın. Difference, Percent ve PercentDiff sıfır tabanlı bir BaseField pivot alanı indeksi ile bir BaseItem bekler. RunTotal için yalnızca BaseField yeterlidir. Satır, sütun, toplam ve indeks modları paydalarını, yapılandırılan birleştirme ile kaynak kayıtlarından türetir
Açık bir BaseItem, taban pivot alanı içindeki sıfır tabanlı bir öğe indeksidir. Bitişik öğe karşılaştırmaları için xlPivotBaseItemPrevious ya da xlPivotBaseItemNext kullanın. Karşılaştırma kesişimi yoksa hücre boş kalır; payda sıfır ise sonuç #DIV/0! olur
DataField := Pivot.AddDataFieldByName('Revenue', xlpaSum);
DataField.ShowDataAs := xlpsdaPercentDiff;
DataField.BaseField := 0;
DataField.BaseItem := xlPivotBaseItemPrevious;
CellsWritten := Pivot.Make(ResultWriter.WriteCell);
Filtreleme, gruplama ve sıralama
Make, etki alanı inşasından önce gizli öğeleri ve sayfa seçimlerini uygular; ardından başlık, tarih, sayı, yüzde, toplam ve değer filtrelerini değerlendirir. Sayısal aralıklar, takvim grupları ve ayrık gruplar, birleştirme öncesinde önbellek alanı gruplama üst verisini kullanır. SortType etiketlerin kararlı sıralamasını seçer; SortDataField ise veri değerlerine göre kararlı sıralama için sıfır tabanlı değer alanını belirler
Hesaplanan ifadeler
Hesaplanan önbellek alanları her kaynak kaydı için bir kez çalışır; hesaplanan öğeler kardeş öğe birleşimleri üzerinden çalışır ve MemberType = 'data' olan hesaplanan üyeler, kaynak birleştirmesinin ardından sanal değer alanları ekler. Formül adları büyük/küçük harfe duyarsızdır ve köşeli parantez ya da tırnak içinde yazılabilir. Aritmetik işlemler, karşılaştırmalar, yüzdeler, parantezler ve yaygın sayısal ile mantıksal işlevler desteklenir; döngüsüz hesaplanan tanımlar için bağımlılık turları tekrarlanır
ProfitField := Pivot.Cache.AddField('Profit', xlpcftNumber);
ProfitField.Formula := '=Revenue-Cost';
ProfitField.DatabaseField := False;
Pivot.AddDataField(Pivot.AddField('Profit', 4), xlpaSum);
RegionField.AddCalculatedItem('Combined', '=North+South');
Pivot.AddCalculatedMember('Margin', '=Profit/Revenue').MemberType := 'data';
Ara toplamlar ve genel toplamlar
Her satır ya da sütun alanı, yapılandırılmış ara toplam işlevlerini ayrıntı öğelerinin altına ya da üstüne Subtotals ve SubtotalTop ile somutlaştırabilir. RowGrandTotals ve ColumnGrandTotals kaydedilen çalışma kitabının politikasını belirler; MaterializeGrandTotalRow ve MaterializeGrandTotalColumn ise sonuç geri çağrılarını, kaynak kayıtlarını yeniden taramadan açık genel toplam çıktısına dahil eder
Genişletilmiş değer gösterme modları
ExtendedShowDataAs; üst öğe yüzdesi, üst satır yüzdesi, üst sütun yüzdesi, kümülatif toplam yüzdesi ile artan veya azalan sıralama (rank) modlarını sunar. Bu modlar XLSX uzantı modelini kullanır ve klasik BIFF'te desteklenmeyen veri alanı değerleri üretmez
Mevcut bir pivot çalışma kitabını inceleme
Workbook.Open('excel-authored-pivot.xls');
for SheetIndex := 1 to Workbook.Sheets.Count do
begin
Sheet := Workbook.Sheets[SheetIndex];
for PivotIndex := 0 to Sheet.PivotTables.Count - 1 do
begin
Pivot := Sheet.PivotTables[PivotIndex];
Writeln(Pivot.Name);
Writeln(Pivot.FieldCount);
if Assigned(Pivot.Cache) then
Writeln(Pivot.Cache.SourceRangeSheet);
end;
end;