企業常需將 Excel 試算表匯入 Oracle,典型痛點:中文欄位名對應、日期/數值格式不一、重複鍵衝突(需更新或插入)。本文提供完整 C# 實作範例,涵 UI 預覽、資料清洗、OleDb 讀取、Oracle 批次 Upsert。
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 預覽與驗證
}
}
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);
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 倍。完整專案原始碼:ImportExcelToOracle.rar