您好:
目前C# 使用 NPOI.XSSF,要來將DB 資料匯出成XLSX
但 1.我先處理 colmnName 在第一行
sheet.GetRow(m_SkipRow).CreateCell( h ).SetCellValue( col.ColumnName );
2.再跑回圈,抓出值,填到EXCEL
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue( dr22[j].ToString() );
但現在只能先用 .ToString() 來填值
可是產生的檔案,數值欄位,就無法用 sum()來加總,只能 用+ 來加總
因為是 文字欄位
因該是,要動態根據 資料類型,去填入值
謝謝
在NPOI.SS.UserModel中有一個void SetCellType(CellType cellType)可以呼叫,CellType也有定義 :
public enum CellType : int
{
Unknown = -1,
Numeric = 0,
String = 1,
Formula = 2,
Blank = 3,
Boolean = 4,
Error = 5
}
我自己的套件在使用後是沒有用處,我查看產出的Excel,每個Cell都是通用格式,或許你可以研究出怎樣調整成功。
我的套件並沒有針對DataTable的資料型態自動處理,只有DataModel會用泛型去因應不同的資料型態,並用不同的CellType產出。
別人的教學 : [C#][NPOI Library] 存取 Excel 檔案利器
我自己寫的套件 : Github : Alien663
您好:
有參考您的範例,先取得型別,設定
sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("#,##0.00");
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(Convert.ToDouble(dr22[j].ToString()));
數值,有出來了
但格式 沒已跑出來,
目前18.00 與 36.01
呈現微
18
36.01
這樣不好看
你似乎少了這行
cell.SetCellType(CellType.Numeric);
另外,你說的問題我有另外修正了一下,看看有沒有符合你的預期。
您好:
我有原來程式 有加,但沒有效過
我先用之前的邏輯 來測試
foreach (DataRow dr22 in dt22.Rows)
{
sheet.CreateRow(m_SkipRow);
for ( int j=0; j< dt22.Columns.Count; j++ ) {
typex=getCellTypeFromType(dt22.Columns[j].DataType.Name);
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellType(typex); //--設定
if (typex == CellType.Numeric)
{
//sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00");
sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("#,##0.00");
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(Convert.ToDouble(dr22[j].ToString()));
}
else {
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(dr22[j].ToString());
}
sheet.SetColumnWidth(j, (dr22[j].ToString().Trim().Length +3 ) * 256);
}//--for
/*
//Format格式為數字
cs.DataFormat = HSSFDataFormat.GetBuiltinFormat("0");
//Format格式為百分比小數兩位
cs.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00%");
*/
m_SkipRow += 1; //--跳一行
}//--foreach (DataRow dr in dt.Rows)
static private CellType getCellTypeFromType(string datatypename)
{
switch (datatypename)
{
case "Decimal":
case "UInt16":
case "UInt32":
case "UInt64":
case "Int16":
case "Int32":
case "Int64":
return CellType.Numeric;
case "Boolean":
return CellType.Boolean;
default:
return CellType.String;
}
}
我有注意到你的資料用的是小數,我當時寫工具時沒注意到,所以前面提到更新的部分就是針對這件事情去做的。
for (int i = 0; i < source.Rows.Count; i++)
{
IRow rows = sheet.CreateRow(headerIndex + 1 + i);
for (int j = 0; j < source.Columns.Count; j++)
{
ICell cell = rows.CreateCell(j);
switch (source.Columns[j].DataType.Name)
{
case "UInt16":
case "UInt32":
case "UInt64":
case "Int16":
case "Int32":
case "Int64":
cell.SetCellType(CellType.Numeric);
cell.SetCellValue(int.Parse(source.Rows[i][j].ToString()));
break;
case "Boolean":
cell.SetCellType(CellType.Boolean);
cell.SetCellValue(Convert.ToBoolean(source.Rows[i][j].ToString()));
break;
case "Double":
case "Decimal":
cell.SetCellType(CellType.Numeric);
cell.SetCellValue(Convert.ToDouble(source.Rows[i][j].ToString()));
break;
default:
cell.SetCellType(CellType.String);
cell.SetCellValue(source.Rows[i][j].ToString());
break;
}
}
}
您好:
我加了
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellType(CellType.Numeric);
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(Convert.ToDouble(dr22[j].ToString()));
結果還是
18
36.01
19
他並不會
18.00
36.01
19.00
謝謝
我測試過後,小數點的部分需要以下的程式碼更改Format。
ICellStyle _doublestyle = workbook.CreateCellStyle();
_doublestyle.DataFormat = workbook.CreateDataFormat().GetFormat("0.0000");
cell.CellStyle = _doublestyle;
您好:
謝謝, 但我試了, 一樣沒有效@@
我測試過了,有可能是因為你的DataTable一開始記錄DataType就只有String,所以怎樣設定都是錯的。
我的測試資料設定如下,取出來的資料如圖。
dtStudent = new DataTable();
dtStudent.Columns.Add("Name");
dtStudent.Columns.Add("Age", typeof(double));
dtStudent.Columns.Add("StudentId", typeof(int));
dtStudent.Columns.Add("Birth", typeof(DateOnly));
dtStudent.Columns.Add("TestTime", typeof(TimeOnly));
dtStudent.Columns.Add("UpdateTime", typeof(DateTime));
您好:
謝謝
因為我是動態產生欄位,所已沒有一個一個設定 dtStudent.Columns.Add("Age", typeof(double));
這樣
而是
static private void setSheet_data(DataRow dr, ISheet sheet, ICellStyle cellStyle, ICellStyle cellStyle_double)
{
//------------------設定Sheet 資料公用程式
int m_SkipRow = 0; //---從哪一行開始,後續+1,跳一行
SqlConnection connection22 = new SqlConnection();
connection22.ConnectionString = con_str;
//----根據傳入的 dr 來做QUERY ,設定sheet
//----1.執行SQL,跑回圈
//----2.設定標題
//----3.迴圈欄位
//------------
string dbname = dr["DBNAME"].ToString();
string queryX = dr["query"].ToString();
queryX = "use " + dbname + "; " + queryX;
//-----1.先抓取要 執行的資料
SqlCommand command = new SqlCommand();
command.CommandText = queryX;
using (SqlDataAdapter dataAdapter = new SqlDataAdapter(command.CommandText, connection22))
{
DataTable dt22 = new DataTable();
dataAdapter.Fill(dt22);
if (dt22.Rows.Count > 0)
{
//---後面要抓欄位 型態
PropertyInfo[] Props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
Int32 h = 0; //----標題
//建制head
//建立第一列,通常拿來設定標題
sheet.CreateRow(m_SkipRow);
foreach (DataColumn col in dt22.Columns)
{
sheet.GetRow(m_SkipRow).CreateCell(h).SetCellValue(col.ColumnName);
h += 1;
}//--
CellType typex; //--類別
m_SkipRow += 1; //--明細 ,先跳一行
//-------2.有資料,就產生workbook
foreach (DataRow dr22 in dt22.Rows)
{
sheet.CreateRow(m_SkipRow);
for (int j = 0; j < dt22.Columns.Count; j++)
{
typex = getCellTypeFromType(dt22.Columns[j].DataType.Name);
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellType(typex); //--設定
if (typex == CellType.Numeric)
{
//sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00");
//sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("#,##0.00");
//sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle = cellStyle_double;
//cell.setCellStyle(cellStyle);
sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle = cellStyle_double;
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellType(CellType.Numeric);
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(Convert.ToDouble(dr22[j].ToString()));
/*
ExcelNumericFormat.applyNumericFormat(outWorkbook, row, cell, Double.valueOf(df.format(10.251)), "#,###.##");
*/
}
else
{
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(dr22[j].ToString());
}
sheet.SetColumnWidth(j, (dr22[j].ToString().Trim().Length + 3) * 256);
}//--for
/*
//Format格式為數字
cs.DataFormat = HSSFDataFormat.GetBuiltinFormat("0");
//Format格式為百分比小數兩位
cs.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00%");
*/
m_SkipRow += 1; //--跳一行
}//--foreach (DataRow dr in dt.Rows)
}//---IF
}//--USING
}//-- static private void setSheet_data
我個別設定欄位的Data Type,是因為我寫單元測試希望是比較pure的環境做測試,所以是直接寫固定的資料才會那樣做,模擬從資料庫拿到資料時的Table。
所以就我的觀察,你可能需要針對以下程式碼設定中斷點,看看你的資料是不是進入你想要的condition,如果每次設定CellType都失敗,那我猜可能資料都是跑到elses那邊去了。
if (typex == CellType.Numeric)
{
//sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00");
//sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("#,##0.00");
//sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle = cellStyle_double;
//cell.setCellStyle(cellStyle);
sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle = cellStyle_double;
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellType(CellType.Numeric);
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(Convert.ToDouble(dr22[j].ToString()));
// ExcelNumericFormat.applyNumericFormat(outWorkbook, row, cell, Double.valueOf(df.format(10.251)), "#,###.##");
}
else
{
sheet.GetRow(m_SkipRow).CreateCell(j).SetCellValue(dr22[j].ToString());
}
您好:
謝謝您
但我實際測試,他都有跑進去 typex == CellType.Numeric 這一段
我後來繼續研究,發現cell.SetCellType
並不是影響最終顯示在excel結果的語法,實際上要讓他以小數後二位顯示,還是要靠format,如以下程式碼:
ICellStyle _doublestyle = workbook.CreateCellStyle();
_doublestyle.DataFormat = workbook.CreateDataFormat().GetFormat("#,##0.00");
比較完整的範例如下,我也有同步更新我的Github專案
switch (source.Columns[j].DataType.Name)
{
case "UInt16":
case "UInt32":
case "UInt64":
case "Int16":
case "Int32":
case "Int64":
ICellStyle _intstyle = workbook.CreateCellStyle();
_intstyle.DataFormat = workbook.CreateDataFormat().GetFormat("#,##0");
cell.CellStyle = _intstyle;
cell.SetCellType(CellType.Numeric);
cell.SetCellValue(int.Parse(source.Rows[i][j].ToString()));
break;
case "Boolean":
cell.SetCellType(CellType.Boolean);
cell.SetCellValue(Convert.ToBoolean(source.Rows[i][j].ToString()));
break;
case "Double":
case "Decimal":
ICellStyle _doublestyle = workbook.CreateCellStyle();
_doublestyle.DataFormat = workbook.CreateDataFormat().GetFormat("#,##0.00");
cell.CellStyle = _doublestyle;
cell.SetCellType(CellType.Numeric);
cell.SetCellValue(Convert.ToDouble(source.Rows[i][j].ToString()));
break;
default:
cell.SetCellType(CellType.String);
cell.SetCellValue(source.Rows[i][j].ToString());
break;
}
您好:
謝謝
這我之前也有先弄了GetFormat
但我發現有一段,我每一個CELL 都用
sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle.DataFormat
sheet.GetRow(m_SkipRow).CreateCell(j).CellStyle
重複sheet.GetRow(m_SkipRow).CreateCell(j) 設定
後來改成
ICell s = sheet.GetRow(m_SkipRow).CreateCell(j);
s.SetCellType(typex);
其他設定都用
s.DataFormat
s.CellStyle
來做設定就過了
謝謝
cell1 = sheet32.GetRow(rowIndex).CreateCell(i);
cell1.SetCellValue(Convert.ToDouble(reader[i].ToString()));