Przejdź do treści stopki
KORZYSTANIE Z IRONXL

Jak utworzyć tabelę przestawną Excel w języku C#?

Tworzenie tabel przestawnych Excel w języku C# działa zarówno z Office Interop (wymagającym instalacji pakietu Microsoft Office), jak i nowoczesnymi bibliotekami, takimi jak IronXL, które działają niezależnie, przy czym IronXL oferuje większą elastyczność wdrożenia i obsługę wielu platform dla środowisk DevOps.

Programowe generowanie tabel przestawnych wymaga albo C# Interop z zależnościami Office, albo nowoczesnych bibliotek, takich jak IronXL, które działają niezależnie. W tym samouczku przedstawiono oba podejścia, podkreślając, dłączego programiści coraz częściej wybierają IronXL zamiast tradycyjnych metod Interop, zwłaszcza podczas wdrażania w kontenerach Docker lub środowiskach chmurowych, takich jak Azure i AWS.

W tym artykułe dowiemy się, jak edytować, tworzyć, projektować i obliczać tabele przestawne oraz grupy z automatyczną analizą i obsługą błędów — a wszystko to przy zachowaniu prostoty wdrożenia, której wymagają inżynierowie DevOps.

Czym jest tabela przestawna w programie Excel?

Tabela przestawna jest jednym z najpotężniejszych narzędzi programu Excel. Jest to łatwy sposób na podsumowanie dużych zbiorów danych, co czyni go nieocenionym narzędziem do analizy danych w aplikacjach .NET. Tabele przestawne pozwalają w łatwy sposób wyświetlać, rozumieć i analizować dane liczbowe. Są one dostępne nie tylko w Excelu, ale także w innych programach, takich jak Arkusze Google, Apple Numbers i eksporty CSV. Zapewniają one rozwiązanie umożliwiające przegląd danych — działają jak konsola danych, pozwalając użytkownikom przeglądać informacje w przejrzysty sposób.

W przypadku aplikacji kontenerowych programowe tworzenie tabel przestawnych eliminuje konieczność instalowania programu Excel w obrazach Docker, co znacznie zmniejsza rozmiar kontenera i złożoność wdrożenia. Takie podejście idealnie wpisuje się w nowoczesne procesy CI/CD oraz strategie wdrażania kontenerów.

Przyjrzyjmy się najpierw niewłaściwemu sposobowi tworzenia tabeli przestawnej, a następnie poznajmy właściwy sposób w języku C#:

Jak utworzyć tabelę przestawną w Excelu przy użyciu C# Interop?

C# Excel Interop zapewnia bezpośredni dostęp do funkcji tabel przestawnych programu Excel poprzez automatyzację COM. Oto tradycyjne podejście, z którym spotyka się wielu programistów, szukając narzędzi do generowania tabel przestawnych w języku C#:

Dłączego to podejście jest uważane za przestarzałe w .NET?

using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
// Create Excel application instance
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Data\SalesData.xlsx");
Excel.Worksheet xlSheet = (Excel.Worksheet)xlWorkbook.Sheets[1];
Excel.Worksheet xlPivotSheet = (Excel.Worksheet)xlWorkbook.Sheets.Add();
// Define data range for pivot table
Excel.Range dataRange = xlSheet.UsedRange;
// Row area and column area 
// Create pivot cache and pivot table
Excel.PivotCache pivotCache = xlWorkbook.PivotCaches().Create(
    Excel.XlPivotTableSourceType.xlDatabase,
    dataRange,
    Type.Missing);
Excel.PivotTable pivotTable = pivotCache.CreatePivotTable(
    xlPivotSheet.Cells[3, 1],
    "SalesPivot",
    Type.Missing,
    Type.Missing); // fields by field
// Configure pivot table fields
Excel.PivotField productField = (Excel.PivotField)pivotTable.PivotFields("Product");
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
productField.Position = 1;
Excel.PivotField regionField = (Excel.PivotField)pivotTable.PivotFields("Region");
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
regionField.Position = 1;
Excel.PivotField salesField = (Excel.PivotField)pivotTable.PivotFields("Sales");
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum);
// Save and cleanup
xlWorkbook.SaveAs(@"C:\Data\PivotReport.xlsx");
xlWorkbook.Close();
xlApp.Quit();
// Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable);
Marshal.ReleaseComObject(pivotCache);
Marshal.ReleaseComObject(xlPivotSheet);
Marshal.ReleaseComObject(xlSheet);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
using Excel = Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices;
// Create Excel application instance
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(@"C:\Data\SalesData.xlsx");
Excel.Worksheet xlSheet = (Excel.Worksheet)xlWorkbook.Sheets[1];
Excel.Worksheet xlPivotSheet = (Excel.Worksheet)xlWorkbook.Sheets.Add();
// Define data range for pivot table
Excel.Range dataRange = xlSheet.UsedRange;
// Row area and column area 
// Create pivot cache and pivot table
Excel.PivotCache pivotCache = xlWorkbook.PivotCaches().Create(
    Excel.XlPivotTableSourceType.xlDatabase,
    dataRange,
    Type.Missing);
Excel.PivotTable pivotTable = pivotCache.CreatePivotTable(
    xlPivotSheet.Cells[3, 1],
    "SalesPivot",
    Type.Missing,
    Type.Missing); // fields by field
// Configure pivot table fields
Excel.PivotField productField = (Excel.PivotField)pivotTable.PivotFields("Product");
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
productField.Position = 1;
Excel.PivotField regionField = (Excel.PivotField)pivotTable.PivotFields("Region");
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
regionField.Position = 1;
Excel.PivotField salesField = (Excel.PivotField)pivotTable.PivotFields("Sales");
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum);
// Save and cleanup
xlWorkbook.SaveAs(@"C:\Data\PivotReport.xlsx");
xlWorkbook.Close();
xlApp.Quit();
// Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable);
Marshal.ReleaseComObject(pivotCache);
Marshal.ReleaseComObject(xlPivotSheet);
Marshal.ReleaseComObject(xlSheet);
Marshal.ReleaseComObject(xlWorkbook);
Marshal.ReleaseComObject(xlApp);
Imports Excel = Microsoft.Office.Interop.Excel
Imports System.Runtime.InteropServices

' Create Excel application instance
Dim xlApp As New Excel.Application()
Dim xlWorkbook As Excel.Workbook = xlApp.Workbooks.Open("C:\Data\SalesData.xlsx")
Dim xlSheet As Excel.Worksheet = CType(xlWorkbook.Sheets(1), Excel.Worksheet)
Dim xlPivotSheet As Excel.Worksheet = CType(xlWorkbook.Sheets.Add(), Excel.Worksheet)

' Define data range for pivot table
Dim dataRange As Excel.Range = xlSheet.UsedRange

' Create pivot cache and pivot table
Dim pivotCache As Excel.PivotCache = xlWorkbook.PivotCaches().Create(Excel.XlPivotTableSourceType.xlDatabase, dataRange, Type.Missing)
Dim pivotTable As Excel.PivotTable = pivotCache.CreatePivotTable(xlPivotSheet.Cells(3, 1), "SalesPivot", Type.Missing, Type.Missing)

' Configure pivot table fields
Dim productField As Excel.PivotField = CType(pivotTable.PivotFields("Product"), Excel.PivotField)
productField.Orientation = Excel.XlPivotFieldOrientation.xlRowField
productField.Position = 1

Dim regionField As Excel.PivotField = CType(pivotTable.PivotFields("Region"), Excel.PivotField)
regionField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField
regionField.Position = 1

Dim salesField As Excel.PivotField = CType(pivotTable.PivotFields("Sales"), Excel.PivotField)
pivotTable.AddDataField(salesField, "Sum of Sales", Excel.XlConsolidationFunction.xlSum)

' Save and cleanup
xlWorkbook.SaveAs("C:\Data\PivotReport.xlsx")
xlWorkbook.Close()
xlApp.Quit()

' Release COM objects to prevent memory leaks
Marshal.ReleaseComObject(pivotTable)
Marshal.ReleaseComObject(pivotCache)
Marshal.ReleaseComObject(xlPivotSheet)
Marshal.ReleaseComObject(xlSheet)
Marshal.ReleaseComObject(xlWorkbook)
Marshal.ReleaseComObject(xlApp)
$vbLabelText   $csharpLabel

Ten przykład Interop tworzy natywną tabelę przestawną programu Excel z produktami w wierszach, regionami w kolumnach i sumą sprzedaży w obszarze danych. Chociaż podejście to jest funkcjonalne, wymaga instalacji pakietu Microsoft Office oraz starannego zarządzania obiektami COM. Dokumentacja Microsoftu wyjaśnia, dłączego takie podejście nie jest nowoczesne. Z punktu widzenia DevOps podejście to jest szczególnie problematyczne, ponieważ nie można go skutecznie konteneryzować — nie można zainstalować pakietu Microsoft Office w kontenerze Docker w systemie Linux ani wdrożyć go w środowiskach bezserwerowych.

Jakie problemy powoduje C# Interop?

Podejście Interop wiąże się z kilkoma istotnymi wyzwaniami, które sprawiają, że nie nadaje się ono do nowoczesnych praktyk DevOps i wdrożeń natywnych dla chmury.

Niestety, Stack Overflow i inne serwisy programistyczne nadal to zalecają, ponieważ są one zablokowane w czasie na wątkach z początku XXI wieku.

Wymagania dotyczące wdrożenia: Wymaga zainstalowania pakietu Microsoft Office na każdym komputerze, na którym uruchamiany jest kod źródłowy, w tym na serwerach produkcyjnych. Powoduje to wzrost kosztów licencji i zwiększa złożoność wdrożenia.

Zarządzanie pamięcią: Obiekty COM muszą być wyraźnie zwalniane za pomocą funkcji Marshal.ReleaseComObject(). Brak nawet jednego obiektu powoduje zawieszenie się procesów Excela w pamięci, co zostało obszernie udokumentówane na Stack Overflow. Rozważmy pamięć podręczną pivot.

Ograniczenia platformy: To rozwiązanie działa wyłącznie w systemie Windows z zainstalowanym pakietem Office. Może to działać niezwykle wolno i prowadzić do wycieków pamięci. Brak obsługi systemów Linux, macOS, kontenerów Docker oraz platform chmurowych, takich jak Azure Functions. To poważnie ogranicza opcje wdrażania i uniemożliwia korzystanie z nowoczesnych platform do orkiestracji kontenerów.

Problemy z wydajnością: Uruchamianie instancji aplikacji Excel jest powolne i wymaga dużych zasobów, zwłaszcza w przypadku przetwarzania po stronie serwera.

Kompatybilność wersji: Różne wersje pakietu Office mogą mieć różne interfejsy COM, co powoduje problemy z kompatybilnością w różnych środowiskach.

W jaki sposób IronXL tworzy tabelę przestawną programowo bez użycia Interop?

IronXL ma inne podejście do tworzenia tabel przestawnych, wykorzystując kod zarządzany bez zależności COM. Chociaż nie tworzy natywnych tabel przestawnych programu Excel, zapewnia zaawansowane możliwości agregacji, idealne do wdrożeń kontenerowych i architektur natywnych dla chmury. Optymalizacje wydajności biblioteki obejmują 40-krotny wzrost prędkości oraz zmniejszenie zużycia pamięci z 19,5 GB do poniżej 1 GB, co czyni ją idealną dla środowisk kontenerowych o ograniczonych zasobach.

Co sprawia, że to podejście jest nowoczesne w przypadku plików XLSX lub XLS?

using IronXL;
using System.Linq;
using System.Data; // Keep this namespace
using static System.Data.DataTableExtensions; // Use 'using static' for DataTableExtensions
class Program
{
    static void Main(string[] args)
    {
        // Load Excel file - no Office required
        WorkBook workbook = WorkBook.Load("SalesData.xlsx");
        WorkSheet dataSheet = workbook.WorkSheets[0];
        // Convert to DataTable for powerful manipulation
        var dataTable = dataSheet.ToDataTable(true); // true = use first row as column headers
        // Create pivot-style aggregation using LINQ
        var pivotData = dataTable.AsEnumerable()
            .GroupBy(row => new {
                Product = row["Product"].ToString(),
                Region = row["Region"].ToString()
            }) //range
            .Select(g => new {
                Product = g.Key.Product,
                Region = g.Key.Region,
                TotalSales = g.Sum(row => Convert.ToDecimal(row["Sales"])),
                AverageSale = g.Average(row => Convert.ToDecimal(row["Sales"])),
                Count = g.Count()
            }); 
        // Create pivot report worksheet
        WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
        // Build cross-tabulation structure
        var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p);
        var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r);
        // Create headers
        pivotSheet["A1"].Value = "Product/Region";
        int col = 2;
        foreach (var region in regions)
        {
            pivotSheet[$"{(char)('A' + col - 1)}1"].Value = region; // string  
            col++;
        }
        // Populate pivot data
        int row = 2;
        foreach (var product in products)
        {
            pivotSheet[$"A{row}"].Value = product;
            col = 2;
            foreach (var region in regions)
            {
                var sales = pivotData
                    .Where(p => p.Product == product && p.Region == region)
                    .Select(p => p.TotalSales)
                    .FirstOrDefault();
                pivotSheet[$"{(char)('A' + col - 1)}{row}"].Value = sales;
                col++;
            }
            row++;
        }
        // Add totals using Excel formulas
        pivotSheet[$"A{row}"].Value = "Total"; // grand totals
        for (int c = 2; c <= regions.Count() + 1; c++)
        {
            pivotSheet[$"{(char)('A' + c - 1)}{row}"].Formula = $"=SUM({(char)('A' + c - 1)}2:{(char)('A' + c - 1)}{row - 1})";
        }
        // Proceeding to apply formatting
        var dataRange = pivotSheet[$"B2:{(char)('A' + regions.Count())}{row}"];
        dataRange.FormatString = "$#,##0.00";
        workbook.SaveAs("PivotReport.xlsx");
    }
}
using IronXL;
using System.Linq;
using System.Data; // Keep this namespace
using static System.Data.DataTableExtensions; // Use 'using static' for DataTableExtensions
class Program
{
    static void Main(string[] args)
    {
        // Load Excel file - no Office required
        WorkBook workbook = WorkBook.Load("SalesData.xlsx");
        WorkSheet dataSheet = workbook.WorkSheets[0];
        // Convert to DataTable for powerful manipulation
        var dataTable = dataSheet.ToDataTable(true); // true = use first row as column headers
        // Create pivot-style aggregation using LINQ
        var pivotData = dataTable.AsEnumerable()
            .GroupBy(row => new {
                Product = row["Product"].ToString(),
                Region = row["Region"].ToString()
            }) //range
            .Select(g => new {
                Product = g.Key.Product,
                Region = g.Key.Region,
                TotalSales = g.Sum(row => Convert.ToDecimal(row["Sales"])),
                AverageSale = g.Average(row => Convert.ToDecimal(row["Sales"])),
                Count = g.Count()
            }); 
        // Create pivot report worksheet
        WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
        // Build cross-tabulation structure
        var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p);
        var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r);
        // Create headers
        pivotSheet["A1"].Value = "Product/Region";
        int col = 2;
        foreach (var region in regions)
        {
            pivotSheet[$"{(char)('A' + col - 1)}1"].Value = region; // string  
            col++;
        }
        // Populate pivot data
        int row = 2;
        foreach (var product in products)
        {
            pivotSheet[$"A{row}"].Value = product;
            col = 2;
            foreach (var region in regions)
            {
                var sales = pivotData
                    .Where(p => p.Product == product && p.Region == region)
                    .Select(p => p.TotalSales)
                    .FirstOrDefault();
                pivotSheet[$"{(char)('A' + col - 1)}{row}"].Value = sales;
                col++;
            }
            row++;
        }
        // Add totals using Excel formulas
        pivotSheet[$"A{row}"].Value = "Total"; // grand totals
        for (int c = 2; c <= regions.Count() + 1; c++)
        {
            pivotSheet[$"{(char)('A' + c - 1)}{row}"].Formula = $"=SUM({(char)('A' + c - 1)}2:{(char)('A' + c - 1)}{row - 1})";
        }
        // Proceeding to apply formatting
        var dataRange = pivotSheet[$"B2:{(char)('A' + regions.Count())}{row}"];
        dataRange.FormatString = "$#,##0.00";
        workbook.SaveAs("PivotReport.xlsx");
    }
}
Imports IronXL
Imports System.Linq
Imports System.Data ' Keep this namespace
Imports static System.Data.DataTableExtensions ' Use 'using static' for DataTableExtensions

Module Program
    Sub Main(args As String())
        ' Load Excel file - no Office required
        Dim workbook As WorkBook = WorkBook.Load("SalesData.xlsx")
        Dim dataSheet As WorkSheet = workbook.WorkSheets(0)
        ' Convert to DataTable for powerful manipulation
        Dim dataTable = dataSheet.ToDataTable(True) ' true = use first row as column headers
        ' Create pivot-style aggregation using LINQ
        Dim pivotData = dataTable.AsEnumerable() _
            .GroupBy(Function(row) New With {
                Key .Product = row("Product").ToString(),
                Key .Region = row("Region").ToString()
            }) _
            .Select(Function(g) New With {
                Key .Product = g.Key.Product,
                Key .Region = g.Key.Region,
                Key .TotalSales = g.Sum(Function(row) Convert.ToDecimal(row("Sales"))),
                Key .AverageSale = g.Average(Function(row) Convert.ToDecimal(row("Sales"))),
                Key .Count = g.Count()
            })
        ' Create pivot report worksheet
        Dim pivotSheet As WorkSheet = workbook.CreateWorkSheet("PivotReport")
        ' Build cross-tabulation structure
        Dim products = pivotData.Select(Function(p) p.Product).Distinct().OrderBy(Function(p) p)
        Dim regions = pivotData.Select(Function(p) p.Region).Distinct().OrderBy(Function(r) r)
        ' Create headers
        pivotSheet("A1").Value = "Product/Region"
        Dim col As Integer = 2
        For Each region In regions
            pivotSheet($"{ChrW(AscW("A"c) + col - 1)}1").Value = region ' string  
            col += 1
        Next
        ' Populate pivot data
        Dim row As Integer = 2
        For Each product In products
            pivotSheet($"A{row}").Value = product
            col = 2
            For Each region In regions
                Dim sales = pivotData _
                    .Where(Function(p) p.Product = product AndAlso p.Region = region) _
                    .Select(Function(p) p.TotalSales) _
                    .FirstOrDefault()
                pivotSheet($"{ChrW(AscW("A"c) + col - 1)}{row}").Value = sales
                col += 1
            Next
            row += 1
        Next
        ' Add totals using Excel formulas
        pivotSheet($"A{row}").Value = "Total" ' grand totals
        For c As Integer = 2 To regions.Count() + 1
            pivotSheet($"{ChrW(AscW("A"c) + c - 1)}{row}").Formula = $"=SUM({ChrW(AscW("A"c) + c - 1)}2:{ChrW(AscW("A"c) + c - 1)}{row - 1})"
        Next
        ' Proceeding to apply formatting
        Dim dataRange = pivotSheet($"B2:{ChrW(AscW("A"c) + regions.Count())}{row}")
        dataRange.FormatString = "$#,##0.00"
        workbook.SaveAs("PivotReport.xlsx")
    End Sub
End Module
$vbLabelText   $csharpLabel

Oto jak tworzyć tabele przestawne w sposób przyjazny dla kontenerów. To podejście działa płynnie w kontenerach Docker, podach Kubernetes i funkcjach bezserwerowych bez żadnych zewnętrznych zależności. Całą aplikację można spakować do lekkiego obrazu kontenera, który działa wszędzie tam, gdzie obsługiwane jest środowisko .NET.

Jak wygląda wynik tabeli przestawnej?

Porównanie oryginalnych danych dotyczących sprzedaży w Excelu i wygenerowanej tabeli przestawnej pokazującej sprzedaż produktów w podziale na regiony wraz z sumami

Wynik pokazuje, w jaki sposób IronXL przekształca surowe dane sprzedażowe w ustrukturyzowany raport przestawny bez konieczności instalowania programu Excel, co czyni go idealnym rozwiązaniem do automatycznego raportowania w potokach CI/CD.

Jak tworzyć dynamiczne podsumowania za pomocą formuł IronXL?

W scenariuszach wymagających dynamicznych aktualizacji, podobnych do funkcji odświeżania tabeli przestawnej, IronXL może wykorzystać wbudowane formuły programu Excel. To podejście jest preferowane — dane są przetwarzane w znacznie bardziej nowoczesny i elegancki sposób. Kod jest łatwy do zrozumieniuiuiuiuia i skonfigurowania bez konieczności kontaktowania się z pomocą techniczną lub czytania instrukcji. Takie podejście jest szczególnie cenne w środowiskach kontenerowych, gdzie potrzebne są obliczenia oparte na formułach, które aktualizują się automatycznie.

W jaki sposób podsumowania oparte na formułach aktualizują się automatycznie?

// Load the workbook
WorkBook workbook = WorkBook.Load(inputPath);
// Rename the first worksheet so formulas reference correctly
WorkSheet dataSheet = workbook.WorkSheets[0];
dataSheet.Name = "DataSheet";
// Convert worksheet to DataTable
DataTable dataTable = dataSheet.ToDataTable(true);
// Create new summary worksheet
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region combinations
var uniqueCombos = dataTable.AsEnumerable()
    .Select(row => new {
        Product = row["Product"].ToString(),
        Region = row["Region"].ToString()
    })
    .Distinct()
    .OrderBy(x => x.Product)
    .ThenBy(x => x.Region);
// Add header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with formulas
int rowIndex = 2;
foreach (var combo in uniqueCombos)
{
    summarySheet[$"A{rowIndex}"].Value = combo.Product;
    summarySheet[$"B{rowIndex}"].Value = combo.Region;
    // Adjust column references if your Sales column is C (not D)
    summarySheet[$"C{rowIndex}"].Formula =
        $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    summarySheet[$"D{rowIndex}"].Formula =
        $"=COUNTIFS(DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    rowIndex++;
}
// Optional: add total row
summarySheet[$"A{rowIndex}"].Value = "Total";
summarySheet[$"C{rowIndex}"].Formula = $"=SUM(C2:C{rowIndex - 1})";
summarySheet[$"D{rowIndex}"].Formula = $"=SUM(D2:D{rowIndex - 1})";
// Save output file
workbook.SaveAs(outputPath);  //filename
// Load the workbook
WorkBook workbook = WorkBook.Load(inputPath);
// Rename the first worksheet so formulas reference correctly
WorkSheet dataSheet = workbook.WorkSheets[0];
dataSheet.Name = "DataSheet";
// Convert worksheet to DataTable
DataTable dataTable = dataSheet.ToDataTable(true);
// Create new summary worksheet
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region combinations
var uniqueCombos = dataTable.AsEnumerable()
    .Select(row => new {
        Product = row["Product"].ToString(),
        Region = row["Region"].ToString()
    })
    .Distinct()
    .OrderBy(x => x.Product)
    .ThenBy(x => x.Region);
// Add header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with formulas
int rowIndex = 2;
foreach (var combo in uniqueCombos)
{
    summarySheet[$"A{rowIndex}"].Value = combo.Product;
    summarySheet[$"B{rowIndex}"].Value = combo.Region;
    // Adjust column references if your Sales column is C (not D)
    summarySheet[$"C{rowIndex}"].Formula =
        $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    summarySheet[$"D{rowIndex}"].Formula =
        $"=COUNTIFS(DataSheet!A:A,\"{combo.Product}\",DataSheet!B:B,\"{combo.Region}\")";
    rowIndex++;
}
// Optional: add total row
summarySheet[$"A{rowIndex}"].Value = "Total";
summarySheet[$"C{rowIndex}"].Formula = $"=SUM(C2:C{rowIndex - 1})";
summarySheet[$"D{rowIndex}"].Formula = $"=SUM(D2:D{rowIndex - 1})";
// Save output file
workbook.SaveAs(outputPath);  //filename
Imports System.Data
Imports System.Linq

' Load the workbook
Dim workbook As WorkBook = WorkBook.Load(inputPath)
' Rename the first worksheet so formulas reference correctly
Dim dataSheet As WorkSheet = workbook.WorkSheets(0)
dataSheet.Name = "DataSheet"
' Convert worksheet to DataTable
Dim dataTable As DataTable = dataSheet.ToDataTable(True)
' Create new summary worksheet
Dim summarySheet As WorkSheet = workbook.CreateWorkSheet("DynamicSummary")
' Get unique product-region combinations
Dim uniqueCombos = dataTable.AsEnumerable() _
    .Select(Function(row) New With {
        .Product = row("Product").ToString(),
        .Region = row("Region").ToString()
    }) _
    .Distinct() _
    .OrderBy(Function(x) x.Product) _
    .ThenBy(Function(x) x.Region)
' Add header row
summarySheet("A1").Value = "Product"
summarySheet("B1").Value = "Region"
summarySheet("C1").Value = "Total Sales"
summarySheet("D1").Value = "Count"
' Populate rows with formulas
Dim rowIndex As Integer = 2
For Each combo In uniqueCombos
    summarySheet($"A{rowIndex}").Value = combo.Product
    summarySheet($"B{rowIndex}").Value = combo.Region
    ' Adjust column references if your Sales column is C (not D)
    summarySheet($"C{rowIndex}").Formula = $"=SUMIFS(DataSheet!C:C,DataSheet!A:A,""{combo.Product}"",DataSheet!B:B,""{combo.Region}"")"
    summarySheet($"D{rowIndex}").Formula = $"=COUNTIFS(DataSheet!A:A,""{combo.Product}"",DataSheet!B:B,""{combo.Region}"")"
    rowIndex += 1
Next
' Optional: add total row
summarySheet($"A{rowIndex}").Value = "Total"
summarySheet($"C{rowIndex}").Formula = $"=SUM(C2:C{rowIndex - 1})"
summarySheet($"D{rowIndex}").Formula = $"=SUM(D2:D{rowIndex - 1})"
' Save output file
workbook.SaveAs(outputPath) ' filename
$vbLabelText   $csharpLabel

Formuły te utrzymują aktywne połączenia z danymi źródłowymi, automatycznie aktualizując się w przypadku zmian w arkuszu danych — podobnie jak w przypadku odświeżania tabeli przestawnej, ale bez zależności Interop. Takie podejście jest idealne dla mikrousług w kontenerach, które muszą generować dynamiczne raporty bez zewnętrznych zależności.

Jakich wyników można oczekiwać od dynamicznych streszczeń?

Jeśli zastosujemy ten kod do przykładowego pliku Excel z poprzedniego przykładu, otrzymamy następujący wynik:

Arkusz kalkulacyjny Excel zawierający dane dotyczące sprzedaży produktów z dynamicznymi formułami podsumowującymi, pokazującymi produkty (laptopy, telefony, tablety) w różnych regionach wraz z obliczonymi sumami i liczbami

Podejście oparte na dynamicznym podsumowaniu zapewnia obliczenia w czasie rzeczywistym, które aktualizują się automatycznie wraz ze zmianami danych źródłowych, co czyni je idealnym rozwiązaniem dla zautomatyzowanych procesów raportowania w środowiskach kontenerowych. Eliminuje to potrzebę planowego odświeżania tabel przestawnych i działa płynnie w aplikacjach .NET MAUI i Blazor.

Jak porównać C# Interop z IronXL w kontekście tabel przestawnych?

Aspect

C# Interop

IronXL

Wymagane biuro

Tak – pełna instalacja

Nie – biblioteka samodzielna

Obsługa platform

Tylko dla systemu Windows

Windows, Linux, macOS, Docker

Zarządzanie pamięcią

Wymagane ręczne czyszczenie COM

Automatyczne zbieranie śmieći w .NET

Wdrożenie

Złożone — licencjonowanie pakietu Office

Proste — pojedyncza biblioteka DLL

Wydajność

Powolne uruchamianie programu Excel

Szybkość — obliczenia w pamięci

Kompatybilność z chmurą

Nie – ograniczenia platformy Azure

Tak — obsługa funkcji Azure

Natywne tabele przestawne

Tak

Nie – alternatywne rozwiązania agregacyjne

Szybkość rozwoju

Powolność – złożoność COM

Szybki – intuicyjny interfejs API

Obsługa kontenerów

Nie – nie można konteneryzować pakietu Office

Tak – gotowe do użycia w Dockerze

Kontrola poprawności

Trudne — monitorowanie procesów COM

Łatwe - Monitorowanie .NET Standard

Z perspektywy DevOps architektura IronXL zapewnia znaczące korzyści w nowoczesnych scenariuszach wdrażania. Możliwość uruchamiania biblioteki w kontenerach bez zewnętrznych zależności oznacza, że można tworzyć lekkie obrazy Docker, które szybko się wdrażają i efektywnie skalują. Kontrole stanu można wdrożyć przy użyciu standardowych wzorców .NET Standard, a funkcje bezpieczeństwa biblioteki obejmują certyfikację DigiCert oraz brak interfejsów COM, co ogranicza wektory ataku.

Które podejście wybrać?

Kiedy należy używać C# Interop?

Wybierz C# Interop, gdy:

  • Niezbędne jest zachowanie natywnych obiektów tabel przestawnych programu Excel
  • Praca wyłącznie w systemie Windows z zainstalowanym pakietem Office
  • Wdrażanie wyłącznie na systemach stacjonarnych, którymi zarządzasz
  • Istniejący kod legacy opiera się na Interop
  • Korzystanie ze starszych wersji .NET Framework
  • Nie planujesz konteneryzacji ani przejścia do chmury

Kiedy IronXL zapewnia lepsze wyniki?

Wybierz IronXL, gdy:

Czego dowiedzieliśmy się o tworzeniu tabel przestawnych w języku C#?

Chociaż C# Excel Interop umożliwia tworzenie natywnych tabel przestawnych, ograniczenia związane z wdrażaniem oraz złożoność tej technologii sprawiają, że staje się ona coraz mniej praktyczna w nowoczesnych aplikacjach, zwłaszcza w środowiskach kontenerowych. IronXL zapewnia potężne alternatywy dzięki agregacji danych i podsumowaniom opartym na formułach, eliminując zależność od pakietu Office przy jednoczesnym zachowaniu możliwości analitycznych.

Dla programistów i inżynierów poszukujących alternatyw dla tworzenia tabel przestawnych bez Interop, IronXL oferuje doskonałe rozwiązanie, które pozwala uniknąć komplikacji związanych z COM, działa na wszystkich platformach i upraszcza wdrażanie. Brak natywnych obiektów tabeli krzyżowej rekompensuje większa elastyczność, lepsza wydajność oraz brak konieczności posiadania licencji na pakiet Office. Co najważniejsze dla zespołów DevOps, IronXL umożliwia prawdziwą infrastrukturę jako kod dzięki wdrożeniom kontenerowym, automatycznemu skalowaniu i płynnej integracji z nowoczesnymi potokami CI/CD.

Kompleksowy zestaw funkcji biblioteki obejmuje formatowanie warunkówe, stylizację komórek, obsługę formuł oraz walidację danych, co czyni ją kompletnym rozwiązaniem do automatyzacji Excela w nowoczesnych aplikacjach .NET. Niezależnie od tego, czy pracujesz z plikami CSV, zarządzasz arkuszami kalkulacyjnymi, czy wdrażasz złożone transformacje danych, IronXL zapewnia spójny, przyjazny dla wdrożeń interfejs API.

Zacznij z IronXL teraz.
green arrow pointer

Chcesz zmodernizować automatyzację w Excelu i tworzyć kod tabel przestawnych w nowoczesnym języku C#?

IronXL można wdrożyć w aplikacjach C# w ciągu kilku sekund za pomocą menedżera pakietów NuGet. Wypróbuj bezpłatną wersję próbną, aby wyeliminować zależności Interop w swoich aplikacjach produkcyjnych i uprościć wdrażanie kontenerów.

Często Zadawane Pytania

Czym jest tabela przestawna w programie Excel?

Tabela przestawna w programie Excel to potężne narzędzie służące do podsumowywania, analizowania, przeglądania i prezentowania danych. Pozwala użytkownikom przekształcać kolumny w wiersze i odwrotnie, umożliwiając dynamiczną analizę danych.

Dlaczego warto używać IronXL do tworzenia tabel przestawnych Excel w języku C#?

IronXL pozwala programistom tworzyć tabele przestawne Excel w języku C# bez konieczności korzystania z Office Interop, co eliminuje potrzebę instalacji programu Excel i zmniejsza zależności, czyniąc go nowoczesnym i wydajnym wyborem.

Jak IronXL wypada w porównaniu z C# Interop w zakresie operacji w programie Excel?

IronXL oferuje bardziej usprawnione i niezależne podejście w porównaniu z C# Interop, które wymaga instalacji pakietu Office. IronXL upraszcza tworzenie tabel przestawnych i innych operacji w programie Excel bez komplikacji związanych z Interop.

Czy mogę generować tabele przestawne bez zainstalowanego programu Excel?

Tak, korzystając z IronXL, można generować tabele przestawne w aplikacjach C# bez konieczności instalowania programu Excel, ponieważ działa on niezależnie od pakietu Microsoft Office.

Czy IronXL nadaje się do dużych zbiorów danych?

IronXL został zaprojektowany do wydajnej obsługi dużych zbiorów danych, dzięki czemu nadaje się do zastosowań wymagających solidnej manipulacji danymi i generowania tabel przestawnych.

Jakie są zalety korzystania z IronXL w porównaniu z tradycyjnymi metodami?

IronXL stanowi nowoczesną, niezależną od innych bibliotek alternatywę dla tradycyjnych metod, takich jak C# Interop, oferując łatwość użytkowania, elastyczność oraz obsługę złożonych operacji na danych bez konieczności instalowania programu Excel.

Czy muszę nauczyć się języka VBA, aby korzystać z IronXL do tworzenia tabel przestawnych?

Nie, IronXL pozwala programistom pracować bezpośrednio w języku C# w celu tworzenia tabel przestawnych i zarządzania nimi, eliminując konieczność nauki języka VBA lub innych języków programowania specyficznych dla programu Excel.

Jordi Bardia
Inżynier oprogramowania
Jordi jest najbardziej biegły w Pythonie, C# i C++. Kiedy nie wykorzystuje swoich umiejętności w Iron Software, programuje gry. Dzieląc odpowiedzialność za testowanie produktów, rozwój produktów i badania, Jordi wnosi ogromną wartość do ciągłej poprawy produktów. Różnorodne doświadczenia ...
Czytaj więcej

Zespol wsparcia Iron

Jestesmy online 24 godziny, 5 dni w tygodniu.
Czat
Email
Zadzwon do mnie