首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

C# 實作 Excel 批量匯入 Oracle 資料庫完整教學:資料預處理、格式驗證與 Upsert 邏輯

     編輯:Oracle 資料庫基礎

專案背景

企業常需將 Excel 試算表匯入 Oracle,典型痛點:中文欄位名對應、日期/數值格式不一、重複鍵衝突(需更新或插入)。本文提供完整 C# 實作範例,涵 UI 預覽、資料清洗、OleDb 讀取、Oracle 批次 Upsert。

前置準備

  1. Excel 欄位標題改為資料庫英文欄位名,刪除多餘欄。
  2. 安裝 Microsoft Access Database Engine(支援 .xls/.xlsx),或使用 EPPlus/NPOI 免元件讀取。
  3. Oracle Client / ODP.NET (Managed/Unmanaged) 已設定連線字串。

核心程式架構

1. 連線字串與資料預覽

private string connStrFmt = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='{0}';Extended Properties='Excel 12.0 Xml;HDR=YES;IMEX=1'";

private void btnPreview_Click(object sender, EventArgs e) {
    using (var conn = new OleDbConnection(string.Format(connStrFmt, txtFilePath.Text))) {
        var da = new OleDbDataAdapter("SELECT * FROM [Sheet1$]", conn);
        var dt = new DataTable();
        da.Fill(dt);
        dataGridView1.DataSource = dt; // UI 預覽與驗證
    }
}

2. 欄位型別識別輔助方法


private static readonly HashSet DateCols = new HashSet(StringComparer.OrdinalIgnoreCase) {
    "PREPARE_DATE","COPY_DATE","COPY_VALIDITY","BUSINESS_VALIDITY",
    "OPENING_APPROVAL_DATE","OPENING_DATE","EDITTIME","LICENSE_DATE",
    "LICENSE_VALIDITY","TEMP_OPENING_DATE","LICENSE_START_DATE","ADDTIME"
};

private static readonly HashSet NumCols = new HashSet(StringComparer.OrdinalIgnoreCase) {
    "FIXED_CAPITAL","REG_CAPITAL","MARGIN","PARK_AREA","PARK_SPACE_NUMBER"
};

private bool IsDateColumn(string col) => DateCols.Contains(col);
private bool IsNumericColumn(string col) => NumCols.Contains(col);

3. Upsert 核心邏輯(逐列組裝 SQL,含格式轉換)


private void ImportData() {
    var dt = (DataTable)dataGridView1.DataSource;
    if (dt == null || dt.Rows.Count == 0) return;

    using (var oraConn = new OracleConnection(ConfigurationManager.ConnectionStrings["OraConn"].ConnectionString)) {
        oraConn.Open();
        int ok = 0, fail = 0;

        foreach (DataRow row in dt.Rows) {
            if (string.IsNullOrWhiteSpace(row[0]?.ToString())) continue; // 跳過空白行

            // 組欄位清單
            var cols = new List { "ID" };
            cols.AddRange(dt.Columns.Cast().Select(c => c.ColumnName));
            string colList = string.Join(",", cols);

            // 組值清單與 UPDATE SET 字串
            var valParts = new List { "SEQ_TBPARK_ENTERPRISE.NEXTVAL" };
            var updParts = new List();

            foreach (DataColumn col in dt.Columns) {
                string raw = row[col].ToString().Replace("<空>", "").Trim();
                string colName = col.ColumnName;

                if (string.IsNullOrEmpty(raw)) {
                    valParts.Add("NULL");
                    updParts.Add($"{colName}=NULL");
                    continue;
                }

                if (IsDateColumn(colName)) {
                    DateTime dtVal = DateTime.Parse(raw);
                    string fmt = dtVal.ToString("yyyy-MM-dd");
                    valParts.Add($"TO_DATE('{fmt}','YYYY-MM-DD')");
                    updParts.Add($"{colName}=TO_DATE('{fmt}','YYYY-MM-DD')");
                }
                else if (IsNumericColumn(colName)) {
                    decimal num = decimal.Parse(raw);
                    valParts.Add(num.ToString());
                    updParts.Add($"{colName}={num}");
                }
                else {
                    string esc = raw.Replace("'", "''");
                    valParts.Add($"'{esc}'");
                    updParts.Add($"{colName}='{esc}'");
                }
            }

            string valList = string.Join(",", valParts);
            string updList = string.Join(",", updParts);
            string keyVal = row["COMPANY_CODE"]?.ToString().Replace("'", "''") ?? "";

            string checkSql = $"SELECT COUNT(*) FROM TBPARK_ENTERPRISE WHERE COMPANY_CODE='{keyVal}'";
            string insertSql = $"INSERT INTO TBPARK_ENTERPRISE ({colList}) VALUES ({valList})";
            string updateSql = $"UPDATE TBPARK_ENTERPRISE SET {updList} WHERE COMPANY_CODE='{keyVal}'";

            using (var cmd = oraConn.CreateCommand()) {
                cmd.CommandText = checkSql;
                bool exists = Convert.ToInt32(cmd.ExecuteScalar()) > 0;
                cmd.CommandText = exists ? updateSql : insertSql;
                try {
                    if (cmd.ExecuteNonQuery() > 0) ok++; else fail++;
                } catch (Exception ex) {
                    fail++;
                    LogHelper.Error(ex, $"SQL: {cmd.CommandText}");
                }
            }
        }
        MessageBox.Show($"成功 {ok} 筆,失敗 {fail} 筆");
    }
}

關鍵優化提醒

  • 批次繫結:大量資料請改用 OracleParameter 陣列繫結 + ArrayBindCount,效能提升 10~100 倍。
  • 交易控制:可每 1000 筆 Commit 一次,平衡效能與可恢復性。
  • 免安裝讀取:推薦 NPOI 或 EPPlus 直接讀 .xlsx,避免需安裝 Access Engine。
  • 錯誤資料導出:失敗列寫入錯誤日誌檔,方便業務人員修正再匯入。

原始碼下載

完整專案原始碼:ImportExcelToOracle.rar

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