一個根據(jù)數(shù)據(jù)庫鏈接字符串,sql語句 即可將結果集導出到Excel的工具 分享,支持sqlserver,mysql。
前因
一個月前朋友找到我,讓我?guī)兔ψ鲆粋€根據(jù)sql導出查詢結果到Excel的工具(之前幫他一個導入Excel然后按其規(guī)則統(tǒng)計數(shù)據(jù)的工具)。
然后扔了我一個SQL語句,瞬間懵比。臥槽。這么多列,我特么得定義這么屬性,改了還得重新改程序(一直用EF)。
于是思考如何忽略列名,進而如何做到通用,做到于我有益,而不是簡單的幫個忙。
如何完成這個需求
Q:程序中根據(jù)SQL查詢出數(shù)據(jù)而不需要關注有哪些列?
A:將查詢結果保存到DataTable中然后遍歷
Q:如何將DataTable轉換Excel?
A:一搜,一試,可用之
Q:如何保存到本地?
A:待我改改寫日志的方法
使用SqlSugar 4.x
進行數(shù)據(jù)操作
SqlSugar 4.x是一款高性能(達到ADO.NET最高性能水平)、輕量級、支持多庫和人性化語法的ORM,語法方便,入門簡單,功能強大。
對數(shù)據(jù)庫結構沒太多要求,支持多主鍵,多自增列
SqlSugar支持sqlserver,mysql故此工具適用于此兩者數(shù)據(jù)庫
0. 創(chuàng)建項目-預覽
1. 到github倉庫clone了源碼至本地生成需要的dll,然后在項目中添加了引用
2. 使用SqlSugar獲取結果到DataTable中(不知道是不是最近幫朋友寫ado.net的代碼寫多了,感覺挺好)
3. DataTable轉Excel
public class DataTableToExcel{ private DataTableToExcel() { } private static DataTableToExcel _instance = null; public static DataTableToExcel Instance { get { if (_instance == null) _instance = new DataTableToExcel(); return _instance; } } /// <summary> /// DataTable通過流導出Excel /// </summary> /// <param name="ds">數(shù)據(jù)源DataSet</param> /// <param name="columns">DataTable中列對應的列名(可以是中文),若為null則取DataTable中的字段名</param> /// <param name="fileName">保存文件名(例如:a.xls)</param> /// <returns></returns> public string StreamExport(DataTable dt, string[] columns = null,string savePath="") { //if (dt.Rows.Count > 65535) //總行數(shù)大于Excel的行數(shù) //{ // throw new Exception("預導出的數(shù)據(jù)總行數(shù)大于excel的行數(shù)"); //} StringBuilder content = new StringBuilder(); content.Append("<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>"); content.Append("<head><title></title><meta http-equiv='Content-Type' content=\"text/html; charset=gb2312\">"); //注意:[if gte mso 9]到[endif]之間的代碼,用于顯示Excel的網(wǎng)格線,若不想顯示Excel的網(wǎng)格線,可以去掉此代碼 content.Append("<!--[if gte mso 9]>"); content.Append("<xml>"); content.Append(" <x:ExcelWorkbook>"); content.Append(" <x:ExcelWorksheets>"); content.Append(" <x:ExcelWorksheet>"); content.Append(" <x:Name>Sheet1</x:Name>"); content.Append(" <x:WorksheetOptions>"); content.Append(" <x:Print>"); content.Append(" <x:ValidPrinterInfo />"); content.Append(" </x:Print>"); content.Append(" </x:WorksheetOptions>"); content.Append(" </x:ExcelWorksheet>"); content.Append(" </x:ExcelWorksheets>"); content.Append("</x:ExcelWorkbook>"); content.Append("</xml>"); content.Append("<![endif]-->"); content.Append("</head><body><table style='border-collapse:collapse;table-layout:fixed;'><tr>"); if (columns != null) { for (int i = 0; i < columns.Length; i++) { if (columns[i] != null && columns[i] != "") { content.Append("<td><b>" + columns[i] + "</b></td>"); } else { content.Append("<td><b>" + dt.Columns[i].ColumnName + "</b></td>"); } } } else { for (int j = 0; j < dt.Columns.Count; j++) { content.Append("<td><b>" + dt.Columns[j].ColumnName + "</b></td>"); } } content.Append("</tr>\n"); for (int j = 0; j < dt.Rows.Count; j++) { content.Append("<tr>"); for (int k = 0; k < dt.Columns.Count; k++) { object obj = dt.Rows[j][k]; Type type = obj.GetType(); if (type.Name == "Int32" || type.Name == "Single" || type.Name == "Double" || type.Name == "Decimal") { double d = obj == DBNull.Value ? 0.0d : Convert.ToDouble(obj); if (type.Name == "Int32" || (d - Math.Truncate(d) == 0)) content.AppendFormat("<td style='vnd.ms-excel.numberformat:#,##0'>{0}</td>", obj); else content.AppendFormat("<td style='vnd.ms-excel.numberformat:#,##0.00'>{0}</td>", obj); } else content.AppendFormat("<td style='vnd.ms-excel.numberformat:@'>{0}</td>", obj); } content.Append("</tr>\n"); } content.Append("</table></body></html>"); content.Replace(" ", ""); using (var w = new StreamWriter(savePath, false, Encoding.UTF8)) { w.WriteLine(content); } return savePath; } }
4. 使用Ini文件保存輸入
public class IniHelper{ // 聲明INI文件的寫操作函數(shù) WritePrivateProfileString() [System.Runtime.InteropServices.DllImport("kernel32")] private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); // 聲明INI文件的讀操作函數(shù) GetPrivateProfileString() [System.Runtime.InteropServices.DllImport("kernel32")] private static extern int GetPrivateProfileString(string section, string key, string def, System.Text.StringBuilder retVal, int size, string filePath); private int retLength = 500; private string sPath = null; public IniHelper(string path, int rl = 500) { this.sPath = path; if (rl > 0) { this.retLength = rl; } } public void WriteValue(string key, string value, string section = "Setting") { // section=配置節(jié),key=鍵名,value=鍵值,path=路徑 WritePrivateProfileString(section, key, value, sPath); } public string ReadValue(string key, string section = "Setting") { // 每次從ini中讀取多少字節(jié) System.Text.StringBuilder temp = new System.Text.StringBuilder(retLength); // section=配置節(jié),key=鍵名,temp=上面,path=路徑 GetPrivateProfileString(section, key, "", temp, retLength, sPath); return temp.ToString(); } }
5. 文本框全選功能
public frmMain() { this.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.Control_ControlAdded); //注冊全選功能 InitializeComponent(); } #region 文本框能夠使用Ctrl+A 全選功能 private void Control_ControlAdded(object sender, ControlEventArgs e) { //使“未來”生效 e.Control.ControlAdded += new System.Windows.Forms.ControlEventHandler(this.Control_ControlAdded); //使“子孫”生效 foreach (Control c in e.Control.Controls) { Control_ControlAdded(sender, new ControlEventArgs(c)); } //使“過去”生效 TextBox textBox = e.Control as TextBox; if (textBox != null) { textBox.KeyPress += TextBox_KeyPress; } } private void TextBox_KeyPress(object sender, KeyPressEventArgs e) { TextBox textBox = sender as TextBox; if (textBox == null) return; if (e.KeyChar == (char)1) { textBox.SelectAll(); e.Handled = true; } } #endregion
6. 打開保存的excel
private void btnOpenDir_Click(object sender, EventArgs e) { var txtFileName = this.txtFileName.Text; var txtExportDir = this.txtExportDir.Text; var openPath = Path.Combine(txtExportDir, txtFileName); if (File.Exists(openPath)) { System.Diagnostics.Process.Start(openPath, "c:\\windows"); } else { AppendTipMsg("文件" + openPath + "不存在"); } }
7. 頁面主要功能代碼
winform中使用多線程時給ui控件賦值
var txtThread = new Thread(() => txtMsg.BeginInvoke(new Action(() => txtMsg.AppendText("向文本框中追加內(nèi)容")))); txtThread.Start();
8. 一些記錄
winform中使用多線程時給ui控件賦值
var txtThread = new Thread(() => txtMsg.BeginInvoke(new Action(() => txtMsg.AppendText("向文本框中追加內(nèi)容")))); txtThread.Start();
源碼中的NopI組件可移除,此工具實際未用到
開啟線程執(zhí)行導出的時候使用的是Task.Run(() =>{});若將框架版本改為4.0則需要將此處修改為new Thread(() =>{}).Start();
整個過程解決了一下問題
數(shù)據(jù)庫查詢(SqlSugar支持sqlserver,mysql)
datatable轉excel文本
ini存取文件
winform文本框全選功能
winform中使用多線程時給ui控件賦值
源碼
下載使用:http://files.cnblogs.com/files/morang/DB數(shù)據(jù)導出工具.rar
源碼下載:http://files.cnblogs.com/files/morang/DB數(shù)據(jù)導出工具_源碼.rar
Coding地址:https://coding.net/u/yimocoding/p/WeDemo/git/tree/NopiExcelDemo
git克隆:git clone https://git.coding.net/yimocoding/WeDemo.git -b NopiExcelDemo
使用說明
作者:易墨
個人小站:http://www.yimo.link
說明:歡迎拍磚,不足之處還望園友們指出;
迷茫大概是因為想的太多做的太少。
http://www.cnblogs.com/morang/p/7112548.html