資料庫一直沒有接觸過,由於工作需要,就進行了一些瞭解。從一開始找資料,到學會基本的編程,大概花了一個半月。其中找資料花的時間最多。這裡我對這一個半月的學習進行總結,希望對新手有協助,也作為資料留檔供以後使用。
vc對資料的操作方式有ODBC DAO OLE/OB和ado等,一開始我都大概看了下,最後選擇了ADO,這個是由於網上介紹,ADO比較有市場。這裡大家可以查看<VC 資料庫編程三部教學(基礎、實踐與進階) >這本書,SCDN上下得到,源碼也有。可以做一個大概瞭解。個人感覺這本書不是很好,上面關於ADO的編程源碼 我沒有看,就看了ADO的介紹。在給大家介紹ADO編程很好的文章寫的很詳細《VC++中使用ADO方式操作ACCESS資料庫》,這篇文章網上隨便可以查到,寫的很詳細,代碼也很全。對於ADO的介紹,網上很多也很詳細。我這裡不再介紹了,我主要對我自己寫的程式進行解讀。
程式中包括了串連資料庫,儲存,查詢,修改等基本的功能。高手就沒必看了,新人個人認為還是有參考價值的。我在CSDN上浪費了很多積分,下載下來的程式,基本都沒用的。最多的是串連資料庫的,但其他動作的比較少。
#import "C://Program Files//Common Files//System//ado//msado15.dll"/<br /> no_namespace /<br /> rename( "EOF", "adoEOF" )
ADO編程
第一步:匯入支援庫檔案
在stdafx.h檔案中
注意粗線的地方msado15.dll是需要的檔案,一般在ado檔案夾下面,最後要注意將eof重新命名,命名可以自己設定。
第二步:初始化智能
CoInitialize (NULL);
這個接觸過COM的肯定知道。在程式結束的地方需要載入
CoUninitialize();
來關閉智能指標。這個只有記的就成,如果要瞭解,看看COM技術方面的資料,有詳細介紹的。
第三步:串連資料庫
try<br />{<br />HRESULT hr = m_connect.CreateInstance(__uuidof(Connection));</p><p>if (FAILED (hr))<br />{<br />m_connect == NULL;<br />AfxMessageBox ("Can't create an instance of Connection");<br />return TRUE;<br />}<br />_bstr_t strconnect =_bstr_t("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=裝置管理.mdb");<br />m_connect->Open(strconnect,_bstr_t (""),_bstr_t (""),adModeUnknown);<br />}<br />catch( _com_error &e )<br />{<br />_bstr_t bstrSource(e.Source());<br />_bstr_t bstrDescription(e.Description());<br />TRACE( "Exception thrown for classes generated by #import" );<br />TRACE( "/tCode = %08lx/n", e.Error());<br />TRACE( "/tCode meaning = %s/n", e.ErrorMessage());<br />TRACE( "/tSource = %s/n", (LPCTSTR) bstrSource);<br />TRACE( "/tDescription = %s/n", (LPCTSTR) bstrDescription);<br />}<br />catch (...)<br />{<br />TRACE ( "*** Unhandled Exception ***" );<br />}
這個try和catch的用法 不是很瞭解,不過貌似很有用的東西,以後要試著多使用使用。catch中的代碼,我是抄一個老外的,也有比較簡單的寫法。
程式中主要的是
HRESULT hr = m_connect.CreateInstance(__uuidof(Connection)); 建立串連指標,其中m_connect為_ConnectionPtr類型。
_bstr_t strconnect =_bstr_t("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=裝置管理.mdb");注意這個必須為_bstr_t 的類型。
m_connect->Open(strconnect,_bstr_t (""),_bstr_t (""),adModeUnknown);串連資料庫。
open函數的參數為 第一個參數:可以為SQL語句,表名,或者命令對象:連接字串由一系列被分隔字元號的parameter = value來組成,如上述程式為例子。ADO可以串連很多資料來源,如mysql等這邊有個j牛逼的人物做個總結,串連為:http://www.codeproject.com/KB/database/connectionstrings.aspx
第二個參數:為useID 第三個參數為PAssWORD 我寫的程式的資料沒有許可權所以沒有這些。
最後一個為 Option:
adModeUnknown:為預設值 (現在我都用這個,具體的要以後多用了才有體會。)
adModeRead:唯讀
adModeWrite:唯寫
adModeReadWrite:讀寫
adModeShareRead:阻止其他Connection對象以讀許可權開啟串連
adModeShareWrite:阻止其他Connection對象以寫入權限開啟串連
adModeShareNone:阻止其他Connection對象以任何許可權開啟串連
adModeShareShareExclusive:阻止其他Connection對象以讀寫權限開啟串連
adConnectUnspecifed:(預設值)同步開啟串連
adAsyncConnect:非同步開啟串連
上述我都是網上找的,就用到一個缺損的。
上述代碼中沒有問題的話,那你就串連資料庫成功了。下面就是其他動作了。
第一 讀資料:
讀寫查詢等都有2種方法,一種是ADO內建的函數,一種是執行SQL;程式中使用的是SQL的方法。這種個人感覺靈活一些,不過好學習SQL語言。
SQL語言執行方法的總體都是一樣的
1) 串連資料來源。也就是上面代碼實現的功能。
2) 定義並建立
定義 _CommandPtr pCommand;//指向Command的指標
_RecordsetPtr pRecordset;//指向Recordset的指標
建立 HRESULT hr = pCommand.CreateInstance(__uuidof(Command));
hr = pRecordset.CreateInstance(__uuidof(Recordset));
3) 將Command的指標和資料來源關聯起來
pCommand->ActiveConnection = m_connect;
4) 添加SQL語句
pCommand->CommandText = (_bstr_t)sql;//你所有的操作差別都在SQL語句用;並注意一定是_bstr_t型的。
5) 執行SQL語句並返回記錄集
pRecordset=pCommand->Execute(NULL,NULL,adCmdText);
注意有些SQL操作是沒有記錄集返回的 如 UPDATA; DELETE等
SQL讀取記錄集的語句
sql = “SELECT * FROM [表名] WHERE 條件”
注意的是如果段名或者表名是中文或者含有 / 空格 等符號的需要用[]括起來
段名 表名 可以用別名的方式 如 sql="SELECT [段名] as name FROM date";
多個表名用“,”分開 如 sql = "SELECT [段名1] as name1, [段名2] as name2 FROM date";
還可以顯示固定的條數 sql = "SELECT TOP 20 * FROM [表名]":表中的前20條記錄
sql = "SELECT TOP 20 PERCENT * FROM [表名]":表中的前20%條記錄
程式中讀取表的前一百條記錄的代碼
//更新view列表<br />//更新view列表<br />CListView* lpview;<br />POSITION pos = GetFirstViewPosition();<br />lpview = (CListView*)GetNextView(pos); //擷取listview的控制代碼<br />CRect rect;<br />CListCtrl& listctrl=(CListCtrl&)lpview->GetListCtrl();<br /> //取得listview中的CListCtrl控制項的控制代碼</p><p>listctrl.GetWindowRect(&rect);<br />listctrl.DeleteAllItems();<br />while(listctrl.DeleteColumn(0));<br />::UpdateWindow(lpview->m_hWnd);<br />//清空view上的內容<br />//資料庫查看檔案<br />m_report = 1;<br /> //2)定義並建立<br />_CommandPtr pCommand;<br />_RecordsetPtr pRecordset;<br />try<br />{<br />HRESULT hr = pCommand.CreateInstance(__uuidof(Command));<br />if (FAILED(hr))<br />{<br />hr=NULL;<br />AfxMessageBox("can't create an instance of Command");<br />return;<br />}<br />//3)關聯資料來源設定SQL語句<br />pCommand->ActiveConnection = m_connect;<br />pCommand->CommandText = "SELECT TOP 100 * FROM [裝置]";<br />hr = pRecordset.CreateInstance(__uuidof(Recordset));<br />if (FAILED(hr))<br />{<br />pRecordset = NULL;<br />AfxMessageBox("can't create an instance of Recordset");<br />return;<br />}<br />//4)執行SQL語句<br />pRecordset=pCommand->Execute(NULL,NULL,adCmdText);<br />int cols = pRecordset->GetFields()->Count;//擷取列數<br />if (data_name!=NULL)<br />{<br />delete []data_name;<br />}<br />data_name = new CString[cols];<br />_variant_t get_name;//這裡需要注意返回的都是_variant_t型的<br />//讀取欄位名<br />for (int i=0;i<cols;i++)<br />{<br />get_name = pRecordset->GetFields()->GetItem(_variant_t(short(i)))->GetName();<br />if (get_name.vt==VT_NULL)//這裡是防止段名為空白直接跳出報錯<br />{<br />data_name[i].Empty();<br />}<br />else<br />data_name[i] = (LPCTSTR)(_bstr_t)get_name;<br />int nWidth = listctrl.GetStringWidth(data_name[i]) + 50;<br />listctrl.InsertColumn(i, data_name[i], LVCFMT_LEFT, nWidth);<br />}<br />int nCount =0;<br />//擷取資料<br />CString lptext;<br />CString k("0");<br />while (!pRecordset->GetadoEOF ())//遍曆記錄集<br />{<br />listctrl.InsertItem(nCount,k);<br />for (i=0;i<cols;i++)<br />{</p><p>get_name = pRecordset->GetFields()->GetItem(_variant_t(short(i)))->GetValue();<br />if (get_name.vt==VT_NULL)//防止記錄集為空白直接跳出報錯<br />{<br />lptext.Empty();<br />}<br />else<br />lptext = (LPCTSTR)(_bstr_t)get_name;<br /> //注意返回的資料類型<br />listctrl.SetItemText(nCount,i,lptext);<br /> //顯示到VIEW中<br />}<br />pRecordset->MoveNext();<br />nCount++;<br />}<br />pRecordset->Close();<br />//delete []lpview;<br />}<br />catch ( _com_error &e )<br />{<br />_bstr_t bstrSource(e.Source());<br />_bstr_t bstrDescription(e.Description());<br />TRACE( "Exception thrown for classes generated by #import" );<br />TRACE( "/tCode = %08lx/n", e.Error());<br />TRACE( "/tCode meaning = %s/n", e.ErrorMessage());<br />TRACE( "/tSource = %s/n", (LPCTSTR) bstrSource);<br />TRACE( "/tDescription = %s/n", (LPCTSTR) bstrDescription);<br />}<br />catch (...)<br />{<br />TRACE ( "*** Unhandled Exception ***" );<br />}
上述代碼中註解的地方 需要注意一下;這些基本是我剛開始寫出現過問題的地方。我上網查詢,也有不少人出現過這樣的錯誤。
第二 查詢
基本步驟和讀取是一樣的SQL的語句為
sql="SELECT * FROM [表名] WHERE 條件";查詢主要是設定 條件子語句
有條件符 >,<,>=,=<=,<>(取反),!>,!<等
範圍運算子(判斷運算式是否在指定範圍)
BETWEEN ... AND ... ;NOT BETWEEN ... AND ...
列表運算子(判斷運算式是否在指定項中)
IN(項1,項2 ...);NOT IN(項1,項2 ...);
模型匹配(判斷是否與指定的字元通配格式符合)LINK , NOT LINK:(這個很有用,我程式中的查詢都是用到他)
空值判斷符(判斷運算式是否為空白):IS NULL,NOT IS NULL
模式比對的萬用字元 %:表示任意類型和長度
底線 _ :匹配單個任一字元
方括弧 []:指定一個字元,字串或範圍,要求匹配對象為定值中的一個
[^]: 要求匹配對象為指定字元外的任意一個
如 LINK '%菜鳥%':就是讀取所有含菜鳥字元的資料
(上述說明是在一個BOLG中看到的忘了 BLOG是哪位大N的 這裡表示感謝。查網路學東西,比只啃書要快好多啊。)
程式碼
_CommandPtr pCommand;<br />_RecordsetPtr pRecordset;<br />try<br />{<br />HRESULT hr = pCommand.CreateInstance(__uuidof(Command));<br />if (FAILED(hr))<br />{<br />hr=NULL;<br />AfxMessageBox("can't create an instance of Command");<br />return;<br />}<br />pCommand->ActiveConnection = m_connect;<br />pCommand->CommandText = (_bstr_t)sql;<br />hr = pRecordset.CreateInstance(__uuidof(Recordset));<br />if (FAILED(hr))<br />{<br />pRecordset = NULL;<br />AfxMessageBox("can't create an instance of Recordset");<br />return;<br />}<br />pRecordset=pCommand->Execute(NULL,NULL,adCmdText);<br />int cols = pRecordset->GetFields()->Count;//擷取列數<br />if (data_name!=NULL)<br />{<br />delete []data_name;<br />}<br />data_name = new CString[cols];<br />_variant_t get_name;<br />//讀取欄位名<br />for (int i=0;i<cols;i++)<br />{<br />get_name = pRecordset->GetFields()->GetItem(_variant_t(short(i)))->GetName();<br />if (get_name.vt==VT_NULL)<br />{<br />data_name[i].Empty();<br />}<br />else<br />data_name[i] = (LPCTSTR)(_bstr_t)get_name;<br />int nWidth = listctrl.GetStringWidth(data_name[i]) + 60;<br />listctrl.InsertColumn(i, data_name[i], LVCFMT_LEFT, nWidth);<br />}<br />int nCount =0;<br />//擷取資料<br />CString lptext;<br />bool f =false;<br />CString k("0");<br />while (!pRecordset->GetadoEOF ())<br />{<br />listctrl.InsertItem(nCount,k);<br />for (int j=0;j<cols;j++)<br />{<br />get_name = pRecordset->GetFields()->GetItem(_variant_t(short(j)))->GetValue();<br />if (get_name.vt==VT_NULL)<br />{<br />lptext.Empty();<br />}<br />else<br />lptext = (LPCTSTR)(_bstr_t)get_name;</p><p>listctrl.SetItemText(nCount,j,lptext);<br />}<br />pRecordset->MoveNext();<br />nCount++;<br />}</p><p>pRecordset->Close();<br />if (nCount==0)<br />{<br />AfxMessageBox("為查到相關資訊,請放寬條件。或確定是否存在記錄");<br />}
上面可以看出用sql執行方式,查詢,讀取基本都差不多,差別在於執行的sql語句;所有對於sql的學習才是以後學習的重點。
第三 添加
sql=sql="INSERT INTO [表名] ([段名1],[段名2]...) VALUES ('值1','值二'...)";後面可以加條件
程式碼
_CommandPtr pCommand;<br />_RecordsetPtr pRecordset;<br />try<br />{<br />HRESULT hr = pCommand.CreateInstance(__uuidof(Command));<br />if (FAILED(hr))<br />{<br />hr=NULL;<br />AfxMessageBox("can't create an instance of Command");<br />return;<br />}<br />pCommand->ActiveConnection = m_connect;<br />pCommand->CommandText = (_bstr_t)sql;<br />hr = pRecordset.CreateInstance(__uuidof(Recordset));<br />if (FAILED(hr))<br />{<br />pRecordset = NULL;<br />AfxMessageBox("can't create an instance of Recordset");<br />return;<br />}<br />pRecordset=pCommand->Execute(NULL,NULL,adCmdText);</p><p>OnDevenceInfo();<br />}
注意的是 添加好像沒有返回集的,反正我試者關閉返回集就報錯。
第四 刪除
sql = "DELETE FROM [表名] WHERE [ID]= '值'";
需要注意的是如果 不限制條件,那麼你整張表的所有資料都會被刪除,這點和後面要說的修改是一樣的;還有如何access自動產生的ID被刪除後是不會再出現的,也就是說1~9中的8被刪除,那麼即使你添加 也是1~7 9~10這樣的。一開始我在刪除的時候,直接和listctrl擷取的行數對於,就會出現錯誤的解決。後面改用擷取ID值做為限制條件,解決問題。(這樣的低價錯誤估計也就我這樣的菜鳥才會犯)。
程式碼
_CommandPtr pCommand;<br />_RecordsetPtr pRecordset;<br />try<br />{<br />HRESULT hr = pCommand.CreateInstance(__uuidof(Command));<br />if (FAILED(hr))<br />{<br />hr=NULL;<br />AfxMessageBox("can't create an instance of Command");<br />return;<br />}<br />pCommand->ActiveConnection = m_connect;<br />pCommand->CommandText = (_bstr_t)sql;<br />hr = pRecordset.CreateInstance(__uuidof(Recordset));<br />if (FAILED(hr))<br />{<br />pRecordset = NULL;<br />AfxMessageBox("can't create an instance of Recordset");<br />return;<br />}<br />pRecordset=pCommand->Execute(NULL,NULL,adCmdText);<br />}
第五 修改
sql="UPDATE [裝置] SET [段名]='值',[段名1]='值1' WHERE 條件"
需注意的是一定要加限制條件,不然你的整張表都將被同一值修改。
程式碼
_CommandPtr pCommand;<br />_RecordsetPtr pRecordset;<br />try<br />{<br />HRESULT hr = pCommand.CreateInstance(__uuidof(Command));<br />if (FAILED(hr))<br />{<br />hr=NULL;<br />AfxMessageBox("can't create an instance of Command");<br />return;<br />}<br />pCommand->ActiveConnection = m_connect;<br />pCommand->CommandText = (_bstr_t)sql;<br />hr = pRecordset.CreateInstance(__uuidof(Recordset));<br />if (FAILED(hr))<br />{<br />pRecordset = NULL;<br />AfxMessageBox("can't create an instance of Recordset");<br />return;<br />}<br />pRecordset=pCommand->Execute(NULL,NULL,adCmdText);<br />}
上面可以看出 對於簡單的資料庫操作,ADO還是比較簡單的,主要的都是一樣的,唯獨差別的是SQL語句。所以我個人感覺對於SQL本身的學習才是將來的重點。
當然ADO的一些其他動作,還要進一步學習才能瞭解。
上述代碼的來源程式在
http://download.csdn.net/source/2791099
希望各位大俠,指出錯誤。如果程式中有問題請提出指正。