首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 高效匯入 Excel 至 Oracle:Sql*Loader 實作完整指南

     編輯:關於C#

將大量 Excel 資料高效匯入 Oracle 資料庫是常見需求。對應 SQL Server 的 SqlBulkCopy,Oracle 提供 Sql*Loader (sqlldr) 工具,雖然設定稍複雜,但效能極佳。實測 1 萬筆資料僅需 4 秒左右,且程式碼可維護性遠優於迴圈拼接 SQL。

實作流程概覽

  1. 使用 COM 元件讀取 Excel,另存為 CSV 格式
  2. 處理 CSV 表頭與最後一欄為 null 的資料問題
  3. 依 Excel 結構建立對應資料表
  4. 產生 Sql*Loader 控制檔
  5. 執行 sqlldr 命令匯入資料

核心程式碼實作

1. Excel 轉 CSV 與資料清理

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));
}

2. 取得 Excel 結構並產生控制檔

// 透過 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));
}

3. 執行 sqlplus 建表與 sqlldr 匯入

// 執行 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 或寫入日誌

效能與優化建議

  • 效能表現:1 萬筆約 4 秒,大量資料匯入首選
  • CSV 處理優化:可改用 TextFieldParser 或第三方函式庫(如 CsvHelper)更健壯地處理逗號、換行、編碼問題
  • 記憶體管理:COM 物件使用後務必釋放,建議搭配 Marshal.ReleaseComObject
  • 錯誤處理:匯入前先驗證資料型別,失敗時保留 bad/discard 檔供除錯

此方案適用於批次匯入、ETL 流程、資料遷移等場景,是 C# 操作 Oracle 大量資料的經典最佳實踐。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved