將大量 Excel 資料高效匯入 Oracle 資料庫是常見需求。對應 SQL Server 的 SqlBulkCopy,Oracle 提供 Sql*Loader (sqlldr) 工具,雖然設定稍複雜,但效能極佳。實測 1 萬筆資料僅需 4 秒左右,且程式碼可維護性遠優於迴圈拼接 SQL。
public void TransferData(string excelFile, string sheetName, string sqlplusString)
{
string dir = Path.GetDirectoryName(excelFile);
string fileName = Path.GetFileNameWithoutExtension(excelFile);
string csvPath = Path.Combine(dir, fileName + ".csv");
string ctlPath = Path.Combine(dir, fileName + ".ctl");
string sqlPath = Path.Combine(dir, fileName + ".sql");
// 清理舊檔
if (File.Exists(csvPath)) File.Delete(csvPath);
// COM 開啟 Excel
var app = new Microsoft.Office.Interop.Excel.Application();
var workbook = app.Workbooks.Open(excelFile);
var worksheet = workbook.Sheets.Cast<Worksheet>()
.FirstOrDefault(s => s.Name.Equals(sheetName, StringComparison.OrdinalIgnoreCase));
if (worksheet == null) throw new Exception($"{sheetName} not found!!");
// 存為 CSV
worksheet.SaveAs(csvPath, XlFileFormat.xlCSV);
workbook.Close(false);
app.Quit();
// 清理 CSV:移除表頭、處理尾端 null 欄位
string content = File.ReadAllText(csvPath, Encoding.GetEncoding("gb2312"));
string data = content.Substring(content.IndexOf("\r\n") + 2).Replace(",\r\n", ",Null");
File.WriteAllBytes(csvPath, Encoding.Default.GetBytes(data));
}
// 透過 OLEDB 取得欄位結構
string connStr = $"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={excelFile};Extended Properties=Excel 8.0;";
using (var conn = new OleDbConnection(connStr))
{
conn.Open();
var schema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns,
new object[] { null, null, sheetName + "$", null });
// 產生 .ctl 控制檔
string control = $@"load data
infile '{csvPath}'
append into table {sheetName}
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"'
(";
foreach (DataRow row in schema.Select("", "Ordinal_Position"))
{
control += row["Column_Name"] + ",";
}
control = control.TrimEnd(',') + ")";
File.WriteAllBytes(ctlPath, Encoding.Default.GetBytes(control));
// 產生建表 SQL
string sql = $@"drop table {sheetName};
create table {sheetName} (";
foreach (DataRow row in schema.Select("", "Ordinal_Position"))
{
sql += row["Column_Name"] + " varchar2(255),";
}
sql = sql.TrimEnd(',') + ");\nexit;";
File.WriteAllBytes(sqlPath, Encoding.Default.GetBytes(sql));
}
// 執行 sqlplus 建立資料表
ExecuteCommand("sqlplus", $"{sqlplusString} @{sqlPath}");
// 執行 sqlldr 匯入資料並捕獲輸出
var proc = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "sqlldr",
Arguments = $"{sqlplusString} {ctlPath}",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
}
};
proc.Start();
string output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit();
// output 可顯示於 UI 或寫入日誌
TextFieldParser 或第三方函式庫(如 CsvHelper)更健壯地處理逗號、換行、編碼問題Marshal.ReleaseComObject此方案適用於批次匯入、ETL 流程、資料遷移等場景,是 C# 操作 Oracle 大量資料的經典最佳實踐。