IronXLを使って C# で Excel のピボットテーブルを作成する方法
Excelでピボットテーブルをプログラムで生成するには、Officeの依存関係を持つC# 相互運用性を使用するか、 IronXLのような独立して動作する最新のライブラリを使用する必要があります。このチュートリアルでは、両方のアプローチを実演し、最新の方法の方が優れている理由を具体的に示します。
サーバーサイドまたはクロスプラットフォームの.NETコードでピボットスタイルのレポートを作成することは、これまで非常に困難でした。 従来のCOM相互運用方式では、Officeが完全にインストールされたWindowsマシンに縛られ、COMクリーンアップ呼び出しを1回でも見落とすとメモリリークが発生し、LinuxやDockerコンテナにデプロイしようとした途端に機能しなくなります。 現代的な代替手段である、 IronXLとLINQを使った集計ロジックの記述は、 .NETが動作する環境であればどこでも実行でき、Officeライセンスも不要で、簡潔で読みやすいコードが得られます。
このガイドでは、両方のテクニックについて詳しく解説します。 生のInteropアプローチを見て、それがなぜ脆弱なのかを正確に理解し、その後、 IronXLを使用してC#で同じピボットスタイルのサマリーシートを作成します。 また、Excelの数式を使用して、実際のピボットテーブルの更新のように動作する、リアルタイムで自動更新される集計表を作成する方法もご紹介します。
Excelのピボットテーブルとは何ですか?
ピボットテーブルは、表計算ソフトにおける最も強力な分析ツールの1つです。 行をグループ化し、値を集計し、結果をクロス集計レイアウトに投影することで、大規模なデータセットを要約します。しかも、数式を一つも手動で記述する必要はありません。 Microsoftの公式ピボットテーブルに関するドキュメントには、Excel内部におけるこの機能の詳細な概要が記載されています。
ピボットテーブルは、Microsoft Excel、Google Sheets、Apple Numbers、その他ほとんどの表計算ソフトに搭載されています。 基本的な考え方は常に同じです。行フィールド、列フィールド、値フィールドを定義すると、ツールがサマリーマトリックスを自動的に作成します。 基となるデータが変更された場合、ピボットテーブルを更新すると、集計結果が自動的に更新されます。
C#のサーバーサイドコードでは、大きく分けて2つの選択肢があります。
- C# 相互運用性 -- COM を介して実行中の Excel プロセスを自動化し、XLSX ファイル内にネイティブのピボットテーブル オブジェクトを作成します。
- IronXLとLINQ集計-- ワークブックをメモリに読み込み、マネージド.NETコードで同じ集計を計算し、結果を新しいワークシートに書き込みます。
どちらの選択肢も有用な出力を生成します。 しかし、現代の導入環境で確実に動作するものは、そのうちの1つだけです。
C# 相互運用性を使用してピボットテーブルを作成するにはどうすればよいですか?
C# Excel Interop を使用すると、COM オートメーションを介して Excel のネイティブなピボットテーブル機能に直接アクセスできます。 オブジェクトを作成し、ワークブックを開き、データ範囲を指すピボット・キャッシュを定義し、行フィールド、列フィールド、データ・フィールドを構成します。
Interopピボットテーブルコードの設定方法
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;
// 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);
// 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;
// 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);
// 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)
この Interop の例では、Product を行に、Region を列に、Sales をデータ領域に合計した Excel ネイティブのピボット・テーブルを作成します。 確かにXLSXファイル内に実際のピボットテーブルオブジェクトを生成するものの、Microsoft Officeがインストールされている必要があり、COMオブジェクトの慎重な管理が求められます。 CODE-42637--@@@の呼び出しを1回でも逃すと、タスクマネージャに古くなったExcelのプロセスが蓄積されていることに気づくでしょう。
コードを書く前にIronXLをインストールする方法
IronXLを使用する前に、 NuGetパッケージマネージャーを使用してライブラリをインストールしてください。
Install-Package IronXL.Excel
dotnet add package IronXL.Excel
Install-Package IronXL.Excel
dotnet add package IronXL.Excel
サーバー、コンテナ、開発マシンにOfficeをインストールする必要はありません。IronXLは、XLSX、XLS、CSVファイルをすべてマネージド.NETメモリ内で読み書きします。
C#相互運用はどのような問題を引き起こしますか?
相互運用性(Interop)のアプローチには、実際の導入段階で急速に複雑化するいくつかの重大な課題が存在する。 Stack Overflowなどのプログラミング関連サイトが依然としてそれを推奨しているのは、多くのスレッドが2000年代初頭に書かれ、その後ロックされているため、アドバイスが時代遅れになっているからだ。
デプロイメントの依存関係- コードを実行するすべてのマシン(本番サーバーやCI/CDビルドエージェントを含む)には、ライセンス版のMicrosoft Officeがインストールされている必要があります。 これはライセンス費用と導入の複雑さを増大させるが、最新の代替手段を用いれば完全に回避できる。
メモリ管理の負担 -- COMオブジェクトは、Marshal.ReleaseComObject()を使用して明示的に解放しなければなりません。 Stack Overflow で詳しく解説されているように、オブジェクトが 1 つでも欠落すると、Excel プロセスがメモリに永久にハングアップします。 長時間稼働するサービスやASP.NET Webアプリケーションでは、これは重大なリソースリークとなる。
プラットフォームの制限事項- Interopは、OfficeがインストールされているWindowsでのみ動作します。 Linux、macOS、Dockerコンテナ、またはAzure FunctionsやAWS Lambdaなどのサーバーレスプラットフォームでは実行できません。 これは、最新のクラウドネイティブアーキテクチャを完全に阻害します。
パフォーマンス上のボトルネック――Excelアプリケーションの起動は時間がかかり、リソースを大量に消費します。数十、数百ものレポートを生成する必要があるサーバーサイドのバッチ処理では、この起動時のオーバーヘッドが深刻なスループットの制約となります。
バージョン互換性の脆弱性― Office のバージョンによって、公開される COM インターフェイスがわずかに異なる。 Office 2019 で動作するコードが、Office 2016 や Microsoft 365 では異なる動作をする可能性があり、展開時にバージョンを固定する方法はありません。 MicrosoftのOffice相互運用アセンブリに関するドキュメントには、これらのバージョン管理上の制約が既知の制限事項として記載されています。
CI/CDの非互換性― ほとんどの継続的インテグレーション環境にはOfficeがインストールされていません。 ピボットテーブル生成コードをテストするには、COMレイヤー全体をモックするか、ライセンス付きのOfficeがインストールされた特別なWindowsエージェントを維持する必要があります。
.NET 6以降( .NET 10を含む)を対象とする新規.NETアプリケーションの場合、これらの制約により、相互運用性(Interop)は現実的な選択肢とは言えません。
IronXLはInteropを使用せずにピボットテーブルを作成するにはどうすればよいですか?
IronXLは、ピボットテーブルの作成において他とは異なるアプローチを採用しています。 IronXLは、COMを介して外部のExcelプロセスを制御するのではなく、ワークブックをマネージド.NETメモリに読み込むことで、セル値、数式、ワークシート構造に直接アクセスできるようにします。 次に、標準的なLINQクエリを使用してピボットスタイルの集計を作成し、その結果を新しいワークシートに書き戻します。
IronXLとLINQを使用してクロス集計サマリーを作成する方法
次の例では、販売データワークブックを読み込み、製品と地域別のクロス集計を計算し、その概要を新しいワークシートに書き込みます。これらすべてをOfficeに依存することなく実行できます。
using IronXL;
using System.Linq;
using System.Data;
// Load Excel file -- no Office installation required
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
WorkSheet dataSheet = workbook.WorkSheets[0];
// Convert to DataTable for flexible LINQ manipulation
var dataTable = dataSheet.ToDataTable(true); // true = first row as column headers
// Build pivot-style aggregation using LINQ grouping
var pivotData = dataTable.AsEnumerable()
.GroupBy(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.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 the pivot report worksheet
WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
// Get distinct row and column values
var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p).ToList();
var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r).ToList();
// Write column headers
pivotSheet["A1"].Value = "Product / Region";
for (int c = 0; c < regions.Count; c++)
{
pivotSheet[$"{(char)('B' + c)}1"].Value = regions[c];
}
// Populate data rows
for (int r = 0; r < products.Count; r++)
{
pivotSheet[$"A{r + 2}"].Value = products[r];
for (int c = 0; c < regions.Count; c++)
{
var sales = pivotData
.Where(p => p.Product == products[r] && p.Region == regions[c])
.Select(p => p.TotalSales)
.FirstOrDefault();
pivotSheet[$"{(char)('B' + c)}{r + 2}"].Value = sales;
}
}
// Add a totals row using Excel SUM formulas
int totalRow = products.Count + 2;
pivotSheet[$"A{totalRow}"].Value = "Total";
for (int c = 0; c < regions.Count; c++)
{
char col = (char)('B' + c);
pivotSheet[$"{col}{totalRow}"].Formula = $"=SUM({col}2:{col}{totalRow - 1})";
}
// Apply currency formatting to the data range
var dataRange = pivotSheet[$"B2:{(char)('B' + regions.Count - 1)}{totalRow}"];
dataRange.FormatString = "$#,##0.00";
workbook.SaveAs("PivotReport.xlsx");
using IronXL;
using System.Linq;
using System.Data;
// Load Excel file -- no Office installation required
WorkBook workbook = WorkBook.Load("SalesData.xlsx");
WorkSheet dataSheet = workbook.WorkSheets[0];
// Convert to DataTable for flexible LINQ manipulation
var dataTable = dataSheet.ToDataTable(true); // true = first row as column headers
// Build pivot-style aggregation using LINQ grouping
var pivotData = dataTable.AsEnumerable()
.GroupBy(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.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 the pivot report worksheet
WorkSheet pivotSheet = workbook.CreateWorkSheet("PivotReport");
// Get distinct row and column values
var products = pivotData.Select(p => p.Product).Distinct().OrderBy(p => p).ToList();
var regions = pivotData.Select(p => p.Region).Distinct().OrderBy(r => r).ToList();
// Write column headers
pivotSheet["A1"].Value = "Product / Region";
for (int c = 0; c < regions.Count; c++)
{
pivotSheet[$"{(char)('B' + c)}1"].Value = regions[c];
}
// Populate data rows
for (int r = 0; r < products.Count; r++)
{
pivotSheet[$"A{r + 2}"].Value = products[r];
for (int c = 0; c < regions.Count; c++)
{
var sales = pivotData
.Where(p => p.Product == products[r] && p.Region == regions[c])
.Select(p => p.TotalSales)
.FirstOrDefault();
pivotSheet[$"{(char)('B' + c)}{r + 2}"].Value = sales;
}
}
// Add a totals row using Excel SUM formulas
int totalRow = products.Count + 2;
pivotSheet[$"A{totalRow}"].Value = "Total";
for (int c = 0; c < regions.Count; c++)
{
char col = (char)('B' + c);
pivotSheet[$"{col}{totalRow}"].Formula = $"=SUM({col}2:{col}{totalRow - 1})";
}
// Apply currency formatting to the data range
var dataRange = pivotSheet[$"B2:{(char)('B' + regions.Count - 1)}{totalRow}"];
dataRange.FormatString = "$#,##0.00";
workbook.SaveAs("PivotReport.xlsx");
Imports IronXL
Imports System.Linq
Imports System.Data
' Load Excel file -- no Office installation required
Dim workbook As WorkBook = WorkBook.Load("SalesData.xlsx")
Dim dataSheet As WorkSheet = workbook.WorkSheets(0)
' Convert to DataTable for flexible LINQ manipulation
Dim dataTable As DataTable = dataSheet.ToDataTable(True) ' True = first row as column headers
' Build pivot-style aggregation using LINQ grouping
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 the pivot report worksheet
Dim pivotSheet As WorkSheet = workbook.CreateWorkSheet("PivotReport")
' Get distinct row and column values
Dim products = pivotData.Select(Function(p) p.Product).Distinct().OrderBy(Function(p) p).ToList()
Dim regions = pivotData.Select(Function(p) p.Region).Distinct().OrderBy(Function(r) r).ToList()
' Write column headers
pivotSheet("A1").Value = "Product / Region"
For c As Integer = 0 To regions.Count - 1
pivotSheet($"{ChrW(AscW("B"c) + c)}1").Value = regions(c)
Next
' Populate data rows
For r As Integer = 0 To products.Count - 1
pivotSheet($"A{r + 2}").Value = products(r)
For c As Integer = 0 To regions.Count - 1
Dim sales = pivotData _
.Where(Function(p) p.Product = products(r) AndAlso p.Region = regions(c)) _
.Select(Function(p) p.TotalSales) _
.FirstOrDefault()
pivotSheet($"{ChrW(AscW("B"c) + c)}{r + 2}").Value = sales
Next
Next
' Add a totals row using Excel SUM formulas
Dim totalRow As Integer = products.Count + 2
pivotSheet($"A{totalRow}").Value = "Total"
For c As Integer = 0 To regions.Count - 1
Dim col As Char = ChrW(AscW("B"c) + c)
pivotSheet($"{col}{totalRow}").Formula = $"=SUM({col}2:{col}{totalRow - 1})"
Next
' Apply currency formatting to the data range
Dim dataRange = pivotSheet($"B2:{ChrW(AscW("B"c) + regions.Count - 1)}{totalRow}")
dataRange.FormatString = "$#,##0.00"
workbook.SaveAs("PivotReport.xlsx")
これは、Excelのネイティブなピボットテーブルから得られるものと同じクロス集計結果を生成します。 セル、数式、書式文字列のすべてをプログラムで完全に制御でき、クリーンアップする必要のあるCOMオブジェクトもありません。
Excelの数式を使って動的な集計表を作成するにはどうすればよいですか?
要約シートを常に最新の状態に保ち、ソースデータが変更されるたびに自動的に再計算を行いたい場合、 IronXLExcelの数式文字列をセルに直接書き込むことができます。 これにより、相互運用性への依存なしに、ピボットテーブルの自動更新と同様の動作を実現できます。
ここで重要な機能は、SUMIFSとCOUNTIFSです。 CODE-42641-- 複数の基準列の条件に基づいて、範囲を合計します; 一致する行を数えます。 どちらも名前付きワークシートへの参照を受け付けるため、サマリーシートからソースデータシートを名前で直接指定できます。
IronXLで数式ベースの集計を作成する方法
using IronXL;
using System.Data;
string inputPath = "SalesData.xlsx";
string outputPath = "DynamicSummary.xlsx";
WorkBook workbook = WorkBook.Load(inputPath);
WorkSheet dataSheet = workbook.WorkSheets[0];
// Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet";
// Convert to DataTable to enumerate unique product/region combinations
DataTable dataTable = dataSheet.ToDataTable(true);
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region pairs
var uniqueCombos = dataTable.AsEnumerable()
.Select(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.Distinct()
.OrderBy(x => x.Product)
.ThenBy(x => x.Region)
.ToList();
// Header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with live SUMIFS / COUNTIFS formulas
for (int i = 0; i < uniqueCombos.Count; i++)
{
int rowIndex = i + 2;
var combo = uniqueCombos[i];
summarySheet[$"A{rowIndex}"].Value = combo.Product;
summarySheet[$"B{rowIndex}"].Value = combo.Region;
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}\")";
}
// Grand total row
int totalRow = uniqueCombos.Count + 2;
summarySheet[$"A{totalRow}"].Value = "Total";
summarySheet[$"C{totalRow}"].Formula = $"=SUM(C2:C{totalRow - 1})";
summarySheet[$"D{totalRow}"].Formula = $"=SUM(D2:D{totalRow - 1})";
workbook.SaveAs(outputPath);
using IronXL;
using System.Data;
string inputPath = "SalesData.xlsx";
string outputPath = "DynamicSummary.xlsx";
WorkBook workbook = WorkBook.Load(inputPath);
WorkSheet dataSheet = workbook.WorkSheets[0];
// Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet";
// Convert to DataTable to enumerate unique product/region combinations
DataTable dataTable = dataSheet.ToDataTable(true);
WorkSheet summarySheet = workbook.CreateWorkSheet("DynamicSummary");
// Get unique product-region pairs
var uniqueCombos = dataTable.AsEnumerable()
.Select(row => new {
Product = row["Product"].ToString(),
Region = row["Region"].ToString()
})
.Distinct()
.OrderBy(x => x.Product)
.ThenBy(x => x.Region)
.ToList();
// Header row
summarySheet["A1"].Value = "Product";
summarySheet["B1"].Value = "Region";
summarySheet["C1"].Value = "Total Sales";
summarySheet["D1"].Value = "Count";
// Populate rows with live SUMIFS / COUNTIFS formulas
for (int i = 0; i < uniqueCombos.Count; i++)
{
int rowIndex = i + 2;
var combo = uniqueCombos[i];
summarySheet[$"A{rowIndex}"].Value = combo.Product;
summarySheet[$"B{rowIndex}"].Value = combo.Region;
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}\")";
}
// Grand total row
int totalRow = uniqueCombos.Count + 2;
summarySheet[$"A{totalRow}"].Value = "Total";
summarySheet[$"C{totalRow}"].Formula = $"=SUM(C2:C{totalRow - 1})";
summarySheet[$"D{totalRow}"].Formula = $"=SUM(D2:D{totalRow - 1})";
workbook.SaveAs(outputPath);
Imports IronXL
Imports System.Data
Imports System.Linq
Dim inputPath As String = "SalesData.xlsx"
Dim outputPath As String = "DynamicSummary.xlsx"
Dim workbook As WorkBook = WorkBook.Load(inputPath)
Dim dataSheet As WorkSheet = workbook.WorkSheets(0)
' Name the data sheet so formula references are stable
dataSheet.Name = "DataSheet"
' Convert to DataTable to enumerate unique product/region combinations
Dim dataTable As DataTable = dataSheet.ToDataTable(True)
Dim summarySheet As WorkSheet = workbook.CreateWorkSheet("DynamicSummary")
' Get unique product-region pairs
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) _
.ToList()
' Header row
summarySheet("A1").Value = "Product"
summarySheet("B1").Value = "Region"
summarySheet("C1").Value = "Total Sales"
summarySheet("D1").Value = "Count"
' Populate rows with live SUMIFS / COUNTIFS formulas
For i As Integer = 0 To uniqueCombos.Count - 1
Dim rowIndex As Integer = i + 2
Dim combo = uniqueCombos(i)
summarySheet($"A{rowIndex}").Value = combo.Product
summarySheet($"B{rowIndex}").Value = combo.Region
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}"")"
Next
' Grand total row
Dim totalRow As Integer = uniqueCombos.Count + 2
summarySheet($"A{totalRow}").Value = "Total"
summarySheet($"C{totalRow}").Formula = $"=SUM(C2:C{totalRow - 1})"
summarySheet($"D{totalRow}").Formula = $"=SUM(D2:D{totalRow - 1})"
workbook.SaveAs(outputPath)
これらの数式は、ソースデータとのリアルタイム接続を維持します。 誰かがDataSheetの値を更新すると、Excelは次のオープンまたは更新時にサマリーを自動的に再計算します。
これを前の例で使用したのと同じ販売データワークブックに適用すると、出力は次のようになります。
How to Create Pivot Table in Excel Using C# 相互運用性 vs IronXL: Image 2 - C# コンテキストに表示される動的なサマリーの出力.
この数式ベースのアプローチでは、 IronXLのセル書式設定APIを使用して、集計セルに条件付き書式、データバー、またはアイコンセットを追加することもできます。これにより、ExcelのUIで手作業を行うことなく、レポートを視覚的に分かりやすくすることができます。
2 つのアプローチを比較するとどうなりますか?
アプローチを選択する前に、それぞれのトレードオフを比較検討することが役立ちます。以下の表は、 .NET本番環境開発において最も重要な要素を網羅しています。
| アスペクト | C# 相互運用性 | IronXL |
|---|---|---|
| オフィス勤務必須 | はい、すべてのマシンに完全インストールします。 | いいえ -- スタンドアロンのNuGetパッケージ |
| プラットフォームのサポート | Windowsのみ | Windows、Linux、macOS、Docker |
| メモリ管理 | 手動のCOMクリーンアップが必要 | 自動 .NET ガベージコレクション |
| 展開の複雑さ | 高レベル - オフィスライセンスとインストール | 低 - 単一のDLL参照 |
| パフォーマンス | 遅い - Excel プロセスの起動オーバーヘッド | 高速 - インメモリ計算 |
| クラウド対応 | いいえ -- Azure Functions、AWS Lambdaではブロックされています | はい、あらゆるクラウドプラットフォームで動作します。 |
| ネイティブピボットテーブルオブジェクト | はい -- 完全な Excel ピボット テーブル | いいえ -- 集計に基づく同等のもの |
| 開発速度 | 遅い - COMの複雑さ | 高速で流暢なマネージドAPI |
| IronWordを.NETプロジェクトにインストールし、Windows環境でWordドキュメントを作成・編集します。 | 限定的 - COM バインディングの問題 | フル -- 最新の.NETをターゲットとしています |
Interopが明確な優位性を持つ唯一のシナリオは、XLSXファイルに埋め込まれたネイティブのExcelピボットテーブルオブジェクトが特に必要な場合です。たとえば、下流のユーザーがExcelの組み込みピボットテーブルUIを使用して操作する必要がある場合(ドリルダウン、フィルタリング、集計関数の対話的な変更など)です。 その他のあらゆるシナリオにおいて、IronXLのアプローチは、記述が速く、展開が容易で、移植性もはるかに高い。
どのアプローチを選ぶべきか?
最適な選択は、導入環境とユーザーのニーズによって異なります。
C# 相互運用性 を選択するのは、以下の条件を満たす場合に限る。
- ユーザーは、Excel UI 内で対話的に操作できるネイティブの Excel ピボットテーブルオブジェクトを必要としています。
- あなたは、すべてのマシンにOfficeがインストールされていることが保証されている、閉鎖的なWindowsデスクトップ環境をターゲットにしています。
- 既にInteropに依存しているレガシーな.NET Frameworkコードを保守しており、現時点では書き換えは正当化されない。
IronXLを選択する場合:
- サーバー、コンテナ、または任意のクラウド環境(Azure、AWS、GCP)にデプロイします。 Linux、macOS、またはDockerベースのビルドに対応したクロスプラットフォームサポートが必要です。 COMライフサイクル管理なしで、クリーンで保守しやすいコードが欲しい。
- .NET 5、6、7、8、9、または10をターゲットにしています
- サーバーインフラストラクチャにおけるMicrosoft Officeのライセンス料を回避したい ファイルごとのExcelプロセス起動なしに、多数のワークブックを高速にバッチ処理する必要があります。
現代の.NETアプリケーションの大部分にとって、 IronXLは実用的な選択肢です。集計ベースの出力は、実際のレポート作成要件をすべて満たし、その見返りとして完全な移植性も得られます。
セル書式設定、数式評価、データ検証、グラフ生成など、その他の機能については、 IronXLのドキュメントおよびIronXLのサンプルライブラリを参照してください。
IronXLを今日から使い始めるにはどうすればいいですか?
IronXLライブラリはNuGetで入手可能で、 .NETプロジェクトへの追加は1分もかかりません。
Install-Package IronXL.Excel
dotnet add package IronXL.Excel
Install-Package IronXL.Excel
dotnet add package IronXL.Excel
インストール後は、既存のワークブックを読み込んだり、新しいワークブックを作成したり、セルの値を読み書きしたり、数式を適用したり、書式文字列を設定したり、XLSX形式で保存したりすることができます。これらすべてを、分かりやすく文書化されたAPIで行うことができます。 COMもOfficeへの依存関係もなく、特別なサーバー設定も不要です。
APIの完全なドキュメントについては、IronXLのスタートガイド、C# Excel Interop移行ガイド、およびIronXLのコード例を参照してください。 IronXLと他のExcelライブラリとの比較については、 IronXL比較記事をご覧ください。
無料トライアルライセンスを利用すれば、購入を決める前に自分のプロジェクトで全機能をテストできます。 本番環境への導入準備が整ったら、商用版のIronXLライセンスをご購入いただくと、試用版のウォーターマークが削除され、優先サポートが受けられます。 無料トライアルから始めて、クロスプラットフォームのExcel自動化がどれほど簡単になるか実感してください。
よくある質問
Interop なしで C# を使用して Excel でピボット テーブルを作成するにはどうすればよいですか?
Office の依存関係に依存せずに強力なデータ操作機能を提供するIronXLを使用すると、相互運用性のない C# を使用して Excel でピボット テーブルを作成できます。
ピボット テーブルを生成するためにIronXLを使用する利点は何ですか?
IronXL を使用すると、開発者は Excel Interop に依存せずにピボット テーブルを生成できるため、Office をインストールする必要がなくなり、展開の複雑さが軽減されます。
IronXLは.NETアプリケーションと互換性がありますか?
はい、 IronXL は.NETアプリケーションと完全に互換性があり、ピボット テーブルの作成を含む Excel 操作用の使いやすい API を提供します。
IronXLではサーバーに Excel をインストールする必要がありますか?
いいえ、 IronXLはサーバーにExcelをインストールする必要はありません。IronXLは独立して機能するため、サーバーサイドアプリケーションにシームレスに統合できます。
IronXLを使用して Excel のデータを操作できますか?
はい、 IronXL は強力なデータ操作機能を提供しており、開発者はピボット テーブルの作成など、Excel データを作成、変更、分析できます。
開発者が従来の相互運用方法よりもIronXL を好むのはなぜでしょうか?
開発者は、Office への依存関係がなく、展開が簡単で、Excel 操作の機能が包括的であるため、従来の相互運用方法よりもIronXL を好む可能性があります。
IronXL はExcel データ操作にどのような機能を提供しますか?
IronXL は、Excel Interop を必要とせずに、Excel ファイルの読み取りと書き込み、スプレッドシートの作成と編集、ピボット テーブルの生成などの機能を提供します。



