導入數據
可以分兩步:1、從 excel 導入數據到 datagridview 控件中,2、從 datagridview 控件導入數據庫
# 1、打開 excel 文件并顯示在dataGridView控件中
excel 導入失敗時:
```
System.InvalidOperationException:“未在本地計算機上注冊“Microsoft.ACE.OLEDB.12.0”提供程序。”
```
此時下載插件安裝,方法如下。
https://blog.csdn.net/stableboy/article/details/80405144
http://www.microsoft.com/downloads/details.aspx?FamilyID=c06b8369-60dd-4b64-a44b-84b371ede16d&displayLang=zh-cn
如果安裝后還是提示“未在本地計算機上注冊“Microsoft.ACE.OLEDB.12.0”,原因是用 64位的系統要啟用 32位的程序,就會出錯。則可以換一種方式啟用:
在visual 的項目屬性設置中,將平臺目標設置為 x64
[https://blog.csdn.net/yyzzhc999/article/details/79367114](https://blog.csdn.net/yyzzhc999/article/details/79367114)


或者調用
C:\Program Files (x86)\Microsoft SQL Server\100\DTS\Binn\DTExec.exe來執行package。

完整代碼如下:
```
public DataSet getData()//獲取數據,這部分單獨寫出來,然后在后續其他地方直接用
{
//1、打開文件
OpenFileDialog fd = new OpenFileDialog();
fd.ShowDialog();
fd.Filter = "Excel(*.xlsx)|*.xlsx|Excel(*.xls)|*.xls"; // filter過濾器,只允許選excel文件
var path = fd.FileName;//獲取文件名
string filesuffix = System.IO.Path.GetExtension(path);//獲取文件擴展名
if (string.IsNullOrEmpty(filesuffix))
{
return null;
}
//2、生成dataset臨時表格
using (DataSet ds = new DataSet())
{
//判斷excel是.xlsx還是.xls,兩個版本的excel處理不一樣
string connString = "";
if(filesuffix == ".xls")
{
connString = "Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=" + path + ";" + ";Extended Properties=\"Excel 8.0;HDR=YES;IMEX=1\"";
}
else
{
connString = "Provider=Microsoft.ACE.OLEDB.12.0;" + "Data Source=" + path + ";" + ";Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\"";
}
//讀取文件
string sql_select = "select * from [sheet1$]";
using (OleDbConnection conn = new OleDbConnection(connString))
using (OleDbDataAdapter da = new OleDbDataAdapter(sql_select, conn)) // 這兩句using之間沒有符號,不然會錯
{
conn.Open();
da.Fill(ds, "from_excel");
}
if(ds == null || ds.Tables.Count <=0)
{
return null;
}
else
{
return ds;
}
}
}
private void btn_打開_Click(object sender, EventArgs e)
{
dataGridView1.DataSource = null;
System.Data.DataTable dt = getData().Tables["from_excel"];
dataGridView1.DataSource = dt;
}
```
# 2、datagridview更新到數據庫
https://blog.csdn.net/xiongyongting/article/details/54170159
https://blog.csdn.net/foreverling/article/details/37376675
https://www.cnblogs.com/kongxiaoshuang/p/6062368.html
# 3、第二步中用數組插入到 c# 的dataGridView 控件中
https://zhidao.baidu.com/question/42361870.html
### 關鍵是設置連接字符串
可以理解為 excel 也是 access 數據庫的一種,所以要提供的是 provider,以及 DataSource

```
private void button1\_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "表格(\*.xls)|\*.xls";
string strPath;
if (ofd.ShowDialog()== DialogResult.OK ;
{
try
{
strPath = ofd.FileName; // 這一行要在打開以后才有,所以不能寫在“if (ofd.ShowDialog()== DialogResult.OK )”前面
string strCon = "provider = microsoft.jet.oledb.4.0; data source = " + strPath + "; extended properties = excel 8.0";
OleDbConnection oleconn = new OleDbConnection(strCon);
string strsql = "select \* from \[Sheet2$\]";
OleDbDataAdapter da = new OleDbDataAdapter(strsql ,strCon);
DataSet ds = new DataSet();
da.Fill(ds, "new\_table3");
dataGridView1.DataSource = ds.Tables\["new\_table3"\];
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
```
# 4、如何真正把 excel 數據更新到數據庫中
參考:項目管理臺賬.csv-登錄窗口
[https://www.cnblogs.com/dylanblog/p/4284016.html](https://www.cnblogs.com/dylanblog/p/4284016.html)
[https://www.cnblogs.com/yechangzhong-826217795/p/11077125.html](https://www.cnblogs.com/yechangzhong-826217795/p/11077125.html)
思路:
1. 導入 excel 表格,形成臨時表 dataTable dt。
2. 從 dt 導入 dbo 中,
不要一條條復制數據,直接批量從 dt 到 dbo!!
以下是錯誤示范:
### 方法 1:sqlAdapter 方法
先寫下面這些

然后再在必要的地方寫一個循環

但有個不好,每次插入一行,都必須打開一次 sql,6000行數據直接卡死。
### 方法 2: 用sqlCommand.ExecuteNonQuery()方法
cmd.ExecuteNonQuery()
也卡死
### 方法 3:用sqlBulkCopy()
[https://www.cnblogs.com/zhaoshujie/p/9691010.html](https://www.cnblogs.com/zhaoshujie/p/9691010.html)
下面這個比較短:
[https://www.cnblogs.com/fanqf/p/9026316.html](https://www.cnblogs.com/fanqf/p/9026316.html)
### 推薦方法 4:用 dt 表更新
1. excel 與dbo分別生成 dt1, dt2

2. 清空 dt2里面的東西,將dt1 里面的東西復制到 dt2中
3. 將dt2更新回數據庫。
詳見
可以封裝ddd(),返回值為 dataTable

然后在 button 中調用 ddd()。

但有個問題,這樣生成以后,ddd 中的da,有可能在 button 就失效了,一旦失效,那么 da 與 dt 脫節,則 dt 就無法通過 da 再更新回數據庫。
> **解決辦法:修改 ddd,使得返回類型為 dataSet,而不是dt,這樣即使脫離 ddd,ds 也可以繼續有效,那么 button 中的 dt 還是可以與數據庫有聯系的,能繼續用**

但也要考慮功能性的問題,如果功能集中,那么就不利于調用。
## 更新遇到問題:
dt 無法更新到 sql 中:如果按下文寫的,那么 da 還是原來的 da,并不是更新以后的。所以這三條語句必須合起來寫。

但不能重復寫兩個 da,怎么辦?解決辦法:前面的用sqlcommand連接。
[https://www.cnblogs.com/MR-Lee/articles/2312062.html](https://www.cnblogs.com/MR-Lee/articles/2312062.html)

> 詳見 連接測試.cs - 導入 excel,或 項目管理臺賬.cs-公共
```
//導入dbo數據
SqlConnection sqlconn = new SqlConnection("server = ");
string pagename = this.tabControl1.SelectedTab.Text;
SqlCommand sqlcomm = new SqlCommand("select \* from dbo.階段評估", sqlconn);
sqlconn.Open();
SqlDataReader sqlrd = sqlcomm.ExecuteReader();
DataTable dt2 = new DataTable();
dt2.Load(sqlrd);
//修改dt中的數據
for (int i = 0; i < dt2.Rows.Count;i++)
{
DataRow dr2 = dt2.Rows\[i\];
if (Convert.ToString( dr2\["項目編號"\]) == "1533023")
{ dr2.Delete(); }
}
//將修改后的dt寫回sql中。這三行一定要寫一起,如果把da寫到前面第一步,則update就毫無意義,因為識別的還是原來沒修改之前的da
SqlDataAdapter da2 = new SqlDataAdapter(sqlcomm);
SqlCommandBuilder sqlcmdB = new SqlCommandBuilder(da2);
da2.Update(dt2);
MessageBox.Show("更新成功");
```
## 問題
System.InvalidOperationException:“對于不返回任何鍵列信息的 SelectCommand,不支持 UpdateCommand 的動態 SQL 生成。”
解決辦法:數據庫主鍵沒設置,要設置好,這樣避免數據重復。
- 幫助文檔 microsoft helo viewer
- c#開發環境及visual studio安裝注意事項
- c#程序基本結構-基本語法
- Q1: public static void main(String[] args) 是什么意思
- Q2: c#命名空間+Main方法
- Q3:注釋+命名規則+代碼規則
- Q4: c#語句 system => console
- Q5: 數據類型 .net
- Q5: 常用名字、變量、運算符
- Q6: 對話窗輸入-屬性
- Q7: 遞歸
- Q8:決策分支、條件判斷語句 if 語句
- Q9:數組
- Q10:字符串
- Q11:對象、類、訪問權限、靜態動態函數
- Q12:方法及參數——繼承于類
- Q13:構造函數
- Q14:繼承——base 關鍵字
- Q15:多態、虛方法、接口
- Q16:創建窗體應用、控件
- Q17:Ado數據訪問、連接 sqlserver 數據庫
- Q18: 讀取數據command + DataRead( )、DataSet + DateAdapter
- Q19: Entity Framwork、entity 與 ADO.net的區別
- Q20: 對話框、文件、文件夾
- Q21: 導入excel數據、更新到 dbo 數據庫中
- Q26: 獲取 excel 中每個 sheet 的表名
- Q22: 兩個窗體之間數據+方法傳遞
- Q23: 數學對象
- Q24: c#網站編寫
- Q25: visual studio2017如何查看幫助
- Q27: c# dictionary 字典對象
- Q28: 數組與dataTable互相轉化