c++使用Accesss資料庫操作Excel表(CRecordset類詳解)
目錄
CRecordset類代表一個記錄集,是MFC的ODBC類中最重要、功能最強大的類。
包含標頭檔案 #include <afxdb.h>
1. 動態集、快照、游標和游標庫
在多工作業系統或網路環境中,多個使用者可以共享同一個資料來源。共享資料的一個主要問題是如何協調各個使用者對資料來源的修改。例如,當某一個應用改變了資料來源中的記錄時,別的連線至該資料來源的應用應該如何處理。對於這個問題,基於MFC的ODBC應用程式可以採取幾種不同的處理辦法,這將由程式採用哪種記錄集決定。
記錄集主要分為快照(Snapshot) 和動態集(Dynaset)兩種,CRecordset類對這兩者都支援。這兩種記錄集的不同表現在它們對別的應用改變資料來源記錄採取了不同的處理方法。
快照型記錄集提供了對資料的靜態視。當別的使用者改變了記錄時(包括修改、新增和刪除),快照中的記錄不受影響,也就是說,快照不反映別的使用者對資料來源記錄的改變,直到呼叫了CRecordset::Requery重新查詢後,快照才會反映變化。對於象產生報告或執行計算這樣的不希望中途變動的工作,快照是很有用的。需要指出的是,快照的這種靜態特性是相對於別的使用者而言的,它會正確反映由本身使用者對記錄的修改和刪除,但對於新新增的記錄直到呼叫Requery後才能反映到快照中。
動態集提供了資料的動態視。當別的使用者修改或刪除了記錄集中的記錄時,會在動態集中反映出來:當滾動到修改過的記錄時對其所作的修改會立即反映到動態集中,當記錄被刪除時,MFC程式碼會跳過記錄集中的刪除部分。對於其它使用者新增的記錄,直到呼叫Requery時,才會在動態集中反映出來。本身應用程式對記錄的修改、新增和刪除會反映在動態集中。當資料必須是動態的時侯,使用動態集是最適合的。例如,在一個火車票聯網售票系統中,顯然應該用動態集隨時反映出共享資料的變化。
在記錄集中滾動,需要有一個標誌來指明滾動後的位置(當前位置)。ODBC驅動程式會維護一個游標,用來跟蹤記錄集的當前記錄,可以把游標理解成跟蹤記錄集位置的一種機制。
游標庫(Cursor Library)是處於ODBC驅動程式管理器和驅動程式之間的動態連結庫(ODBCCR32.DLL)。游標庫的主要功能是支援快照以及為底層驅動程式提供雙向滾動能力,高層次的驅動程式不需要游標庫,因為它們是可滾動的。游標庫管理快照記錄的緩衝區,該緩衝區反映本程式對記錄的修改和刪除,但不反映其它使用者對記錄的改變,由此可見,快照實際上相當於當前的游標庫緩衝區。
應注意的是,快照是一種靜態游標(Static Cursor)。靜態游標直到滾動到某個記錄才能取得該記錄的資料。因此,要保證所有的記錄都被快照,可以先滾動到記錄集的末尾,然後再滾動到感興趣的第一個記錄上。這樣做的缺點是滾動到末尾需要額外的開銷,會降低效能。
與快照不同,動態集不用游標庫維持的緩衝區來存放記錄。實際上,動態集是不使用游標庫的,因為游標庫會遮蔽掉一些支援動態集的底層驅動程式功能。動態集是一種鍵集驅動游標(Keyset-Driven Cursor),當開啟一個動態集時,驅動程式儲存記錄集中每個記錄的鍵。只要游標在動態集中滾動,驅動程式就會通過鍵來從資料來源中檢取當前記錄,從而保證選取的記錄與資料來源同步。
從上面的分析中可以看出,快照和動態集有一個共同的特點,那就是在建立記錄集後,記錄集中的成員就已經確定了。這就是為什麼兩種記錄集都不能反映別的使用者新增記錄的原因。
2. 域資料成員與資料交換
CRecordset類代表一個記錄集。使用者一般需要用ClassWizard建立一個CRecordset的派生類。ClassWizard可以為派生的記錄集類建立一批資料成員,這些資料成員與記錄的各欄位相對應,被稱為欄位資料成員或域資料成員。例如,對於表1所示的將在後面例子中使用的資料庫表,ClassWizard會在派生類中加入6個域資料成員,如清單1所示。可以看出域資料成員與表中的欄位名字類似,且型別匹配。
(表1)stdreg32.mdb中的Section表
CourseID (Text) |
SectionNo (Text) |
InstructorID (Text) |
RoomNo (Text) |
Schedule (Text) |
Capacity (int) |
MATH101 |
1 |
KLAUSENJ |
KEN-12 |
MWF10-11 |
40 |
MATH101 |
2 |
ROGERSN |
WIL-1088 |
TTH3:30-5 |
15 |
MATH201 |
1 |
ROGERSN |
WIL-1034 |
MWF2-3 |
20 |
MATH201 |
2 |
SMITHJ |
WIL-1054 |
MWF3-4 |
25 |
MATH202 |
1 |
KLA |
WIL-1054 |
MWF9-10 |
20 |
MATH202 |
2 |
ROGERSN |
KEN-12 |
TTH9:30-11 |
15 |
MATH202 |
3 |
KLAUSENJ |
WIL-2033 |
TTH3-4:30 |
15 |
(清單1)派生類中的域資料成員
class CSectionSet : public CRecordset
{
public:
……
//{{AFX_FIELD(CSectionSet, CRecordset)
CString m_CourseID;
CString m_SectionNo;
CString m_InstructorID;
CString m_RoomNo;
CString m_Schedule;
int m_Capacity;
//}}AFX_FIELD
……
};
域資料成員用來儲存某條記錄的各個欄位,它們是程式與記錄之間的緩衝區。域資料成員代表當前記錄,當在記錄集中滾動到某一記錄時,框架自動地把記錄的各個欄位拷貝到記錄集物件的域資料成員中。當用戶要修改當前記錄或增加新記錄時,程式先將各欄位的新值放入域資料成員中,然後呼叫相應的CRecordset成員函式把域資料成員設定到資料來源中。
不難看出,在記錄集與資料來源之間有一個數據交換問題。CRecordset類使用“記錄域交換”(Record Field Exchange,縮寫為RFX)機制自動地在域資料成員和資料來源之間交換資料。RFX機制與對話資料交換(DDX)類似。CRecordset的成員函式DoFieldExchange負責資料交換任務,在該函式中呼叫了一系列RFX函式。當用戶用ClassWizard加入域資料成員時,ClassWizard會自動在DoFieldExchange中建立RFX。典型DoFieldExchange如清單2所示:
(清單2)典型的DoFieldExchange函式
void CSectionSet::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CSectionSet)
pFX->SetFieldType(CFieldExchange::outputColumn);
RFX_Text(pFX, _T("[CourseID]"), m_CourseID);
RFX_Text(pFX, _T("[SectionNo]"), m_SectionNo);
RFX_Text(pFX, _T("[InstructorID]"), m_InstructorID);
RFX_Text(pFX, _T("[RoomNo]"), m_RoomNo);
RFX_Text(pFX, _T("[Schedule]"), m_Schedule);
RFX_Int(pFX, _T("[Capacity]"), m_Capacity);
//}}AFX_FIELD_MAP
}
3. SQL查詢
記錄集的建立實際上主要是一個查詢過程,SQL的SELECT語句用來查詢資料來源。在建立記錄集時,CRecordset會根據一些引數構造一個SELECT語句來查詢資料來源,並用查詢的結果建立記錄集。明白這一點對理解CRecordset至關重要。SELECT語句的句法如下:
SELECT rfx-field-list FROM table-name [WHERE m_strFilter]
[ORDER BY m_strSort]
其中table-name是表名,rfx-field-list是選擇的列(欄位),WHERE和ORDER BY是兩個子句,分別用來過濾和排序。下面是SELECT語句的一些例子:
SELECT CourseID, InstructorID FROM Section
SELECT * FROM Section WHERE CourseID='MATH202’AND Capacity=15
SELECT InstructorID FROM Section ORDER BY CourseID ASC
其中第一個語句從Section表中選擇CourseID和InstructorID欄位。第二個語句從Section表中選擇CourseID為MATH202且Capacity等於15的記錄,在該語句中使用了象“AND”或“OR”這樣的邏輯連線符。要注意在SQL語句中引用字串、日期或時間等型別的資料時要用單引號括起來,而數值型資料則不用。第三個語句從Section表中選擇InstructorID列並且按CourseID的升序排列,若要降序排列,可使用關鍵字DESC。
提示:如果列名或表名中包含有空格,則必須用方括號把該名稱包起來。例如,如果有一列名為“Client Name”,則應該寫成“[Client Name]”。
4. 記錄集的建立和關閉
要建立記錄集,首先要構造一個CRecordset派生類物件,然後呼叫Open成員函式查詢資料來源中的記錄並建立記錄集。在Open函式中,可能會呼叫GetDefaultConnect和GetDefaultSQL函式。函式的宣告為:
CRecordset(CDatabase* pDatabase=NULL);
引數pDatabase指向一個CDatabase物件,用來獲取資料來源。如果pDatabase為NULL,則會在Open函式中自動構建一個CDatabase物件。如果CDatabase物件還未與資料來源連線,那麼在Open函式中會建立連線,連線字串由成員函式GetDefaultConnect提供。
virtual CString GetDefaultConnect( );
該函式返回預設的連線字串。Open函式在必要的時侯會呼叫該函式獲取連線字串以建立與資料來源的連線。一般需要在CRecordset派生類中覆蓋該函式並在新版的函式中提供連線字串。
virtual BOOL Open( UINT nOpenType = AFX_DB_USE_DEFAULT_TYPE, LPCTSTR lpszSQL = NULL, DWORD dwOptions = none );
throw( CDBException, CMemoryException );
該函式使用指定的SQL語句查詢資料來源中的記錄並按指定的型別和選項建立記錄集。引數nOpenType說明了記錄集的型別,如表3所示,如果要求的型別驅動程式不支援,則函式將產生一個異常。引數lpszSQL是一個SQL的SELECT語句,或是一個表名。函式用lpszSQL來進行查詢,如果該引數為NULL,則函式會呼叫GetDefaultSQL獲取預設的SQL語句。引數dwOptions可以是一些選項的組合,常用的選項在表4中列出。若建立成功則函式返回TRUE,若函式呼叫了CDatabase::Open且返回FALSE,則函式返回FALSE。
(表3)記錄集的型別
型別 |
含義 |
AFX_DB_USE_DEFAULT_TYPE |
使用預設值。 |
CRecordset::dynaset |
可雙向滾動的動態集。 |
CRecordset::snapshot |
可雙向滾動的快照。 |
CRecordset::dynamic |
提供比動態集更好的動態特性,大部分ODBC驅動程式不支援這種記錄集。 |
CRecordset::forwardOnly |
只能前向滾動的只讀記錄集。 |
(表4)建立記錄集時的常用選項
選項 |
含義 |
CRecordset::none |
無選項(預設)。 |
CRecordset::appendOnly |
不允許修改和刪除記錄,但可以新增記錄。 |
CRecordset::readOnly |
記錄集是隻讀的。 |
CRecordset::skipDeletedRecords |
有些資料庫(如FoxPro)在刪除記錄時並不真刪除,而是做個刪除標記,在滾動時將跳過這些被刪除的記錄。 |
virtual CString GetDefaultSQL( );
Open函式在必要時會呼叫該函式返回預設的SQL語句或表名以查詢資料來源中的記錄。一般需要在CRecordset派生類中覆蓋該函式並在新版的函式中提供SQL語句或表名。
下面是一些返回字串的例子。
“Section” //選擇Section表中的所有記錄到記錄集中
“Section, Course” //合併Section表和Course表的各列到記錄集中
//對Section表中的所有記錄按CourseID的升序進行排序,然後建立記錄集
“SELECT * FROM Section ORDER BY CourseID ASC”
上面的例子說明,通過合理地安排SQL語句和表名,Open函式可以十分靈活地查詢資料來源中的記錄。使用者可以合併多個表的欄位,也可以只選擇記錄中的某些欄位,還可以對記錄進行過濾和排序。
前面說過,在建立記錄集時,CRecordset會構造一個SELECT語句來查詢資料來源。如果在呼叫Open時只提供了表名,那麼SELECT語句還缺少選擇列引數rfx-field-list。框架規定,如果只提供了表名,則選擇列的資訊從DoFieldExchange中的RFX語句裡提取。例如,如果在呼叫Open時只提供了“Section”表名,那麼將會構造如下一個SELECT語句:
SELECT CourseID,SectionNo,InstructorID,RoomNo,Schedule,Capacity FROM Section
建立記錄集後,使用者可以隨時呼叫Requery成員函式來重新查詢和建立記錄集。Requery有兩個重要用途:
· 使記錄集能反映使用者對資料來源的改變。
· 按照新的過濾或排序方法查詢記錄並重新建立記錄集。
在呼叫Requery之前,可呼叫CanRestart來判斷記錄集是否支援Requery操作。要記住Requery只能在成功呼叫Open後呼叫,所以程式應呼叫IsOpen來判斷記錄集是否已建立。函式的宣告為
virtual BOOL Requery( );
throw( CDBException,CMemoryException );
返回TRUE表明記錄集建立成功,否則返回FALSE。若函式內部出錯則產生異常。
BOOL CanRestart( ) const; //若支援Requery則返回TRUE
BOOL IsOpen( ) const; //若記錄集已建立則返回TRUE
CRecordset類有兩個公共資料成員m_strFilter和m_strSort用來設定對記錄的過濾和排序。在呼叫Open或Requery前,如果在這兩個資料成員中指定了過濾或排序,那麼Open和Requery將按這兩個資料成員指定的過濾和排序來查詢資料來源。
成員m_strFilter用於指定過濾器。m_strFilter實際上包含了SQL的WHERE子句的內容,但它不含WHERE關鍵字。使用m_strFilter的一個例子為:
m_pSet->m_strFilter=“CourseID=‘MATH101’”; //只選擇CourseID為MATH101的記錄
if(m_pSet->Open(CRecordset::snapshot,“Section”))
……
成員m_strSort用於指定排序。m_strSort實際上包含了ORDER BY子句的內容,但它不含ORDER BY關鍵字。m_strSort的一個例子為
m_pSet->m_strSort=“CourseID DESC”; //按CourseID的降序排列記錄
m_pSet->Open();
……
事實上,Open函式在構造SELECT語句時,會把m_strFilter和m_strSort的內容放入SELECT語句的WHERE和ORDER BY子句中。如果在Open的lpszSQL引數中已包括了WHERE和ORDER BY子句,那麼m_strFilter和m_strSort必需為空。
呼叫無引數成員函式Close可以關閉記錄集。在呼叫了Close函式後,程式可以再次呼叫Open建立新的記錄集。CRecordset的解構函式會呼叫Close函式,所以當刪除CRecordset物件時記錄集也隨之關閉。
5. 滾動記錄
CRecordset提供了幾個成員函式用來在記錄集中滾動,如下所示。當用這些函式滾動到一個新記錄時,框架會自動地把新記錄的內容拷貝到域資料成員中。
l void MoveNext( ); //前進一個記錄
l void MovePrev( ); //後退一個記錄
l void MoveFirst( ); //滾動到記錄集中的第一個記錄
l void MoveLast( ); //滾動到記錄集中的最後一個記錄
l void SetAbsolutePosition( long nRows );//該函式用於滾動到由引數nRows指定的絕對位置處。若nRows為負數,則從後往前滾動。例如,當nRows為-1時,函式就滾動到記錄集的末尾。注意,該函式不會跳過被刪除的記錄。
l virtual void Move( long nRows, WORD wFetchType = SQL_FETCH_RELATIVE );//該函式功能強大。通過將wFetchType引數指定為SQL_FETCH_NEXT、SQL_FETCH_PRIOR、SQL_FETCH_FIRST、SQL_FETCH_LAST和SQL_FETCH_ABSOLUTE,可以完成上面五個函式的功能。若wFetchType為SQL_FETCH_RELATIVE,那麼將相對當前記錄移動,若nRows為正數,則向前移動,若nRows為負數,則向後移動。
如果在建立記錄集時選擇了CRecordset::skipDeletedRecords選項,那麼除了SetAbsolutePosition外,在滾動記錄時將跳過被刪除的記錄,這一點對於象FoxPro這樣的資料庫十分重要。
如果記錄集是空的,那麼呼叫上述函式將產生異常。另外,必須保證滾動沒有超出記錄集的邊界。
呼叫IsEOF和IsBOF可以進行這方面的檢測。
l BOOL IsEOF( ) const;//如果記錄集為空或滾動過了最後一個記錄,那麼函式返回TRUE,否則返回FALSE。
l BOOL IsBOF( ) const;//如果記錄集為空或滾動過了第一個記錄,那麼函式返回TRUE,否則返回FALSE。
下面是一個使用IsEOF的例子:
while(!m_pSet->IsEOF( ))
m_pSet->MoveNext( );
l long GetRecordCount( ) const;// 呼叫GetRecordCount可獲得記錄集中的記錄總數。
要注意這個函式返回的實際上是使用者在記錄集中滾動的最遠距離。要想真正返回記錄總數,只有呼叫MoveNext移動到記錄集的末尾(MoveLast不行)。
6. 修改、新增和刪除記錄
要修改當前記錄,應該按下列步驟進行:
l 呼叫Edit成員函式。呼叫該函式後就進入了編輯模式,程式可以修改域資料成員。注意不要在一個空的記錄集中呼叫Edit,否則會產生異常。Edit函式會把當前域資料成員的內容儲存在一個緩衝區中,這樣做有兩個目的,一是可以與域資料成員作比較以判斷哪些欄位被改變了,二是在必要的時侯可以恢復域資料成員原來的值。若再次呼叫Edit,則將從緩衝區中恢復域資料成員,呼叫後程序仍處於編輯模式。呼叫Move(AFX_MOVE_REFRESH)或Move(0)可退出編輯模式(AFX_MOVE_REFRESH的值為0),同時該函式會從緩衝區中恢復域資料成員。
l 設定域資料成員的新值。
l 呼叫Update完成編輯。Update把變化後的記錄寫入資料來源並結束編輯模式。
要向記錄集中新增新的記錄,應該按下列步驟進行:
l 呼叫AddNew成員函式。呼叫該函式後就進入了新增模式,該函式把所有的域資料成員都設定成NULL(注意,在資料庫術語中,NULL是指沒有值,這與C++的NULL是不同的)。與Edit一樣,AddNew會把當前域資料成員的內容儲存在一個緩衝區中,在必要的時侯,程式可以再次呼叫AddNew取消新增操作並恢復域資料成員原來的值,呼叫後程序仍處於新增模式。呼叫Move(AFX_MOVE_REFRESH)可退出新增模式,同時該函式會從緩衝區中恢復域資料成員。
l 設定域資料成員。
l 呼叫Update。Update把域資料成員中的內容作為新記錄寫入資料來源,從而結束了新增。
如果記錄集是快照,那麼在新增一個新的記錄後,需要呼叫Requery重新查詢,因為快照無法反映新增操作。
要刪除記錄集的當前記錄,應按下面兩步進行:
l 呼叫Delete成員函式。該函式會同時給記錄集和資料來源中當前記錄加上刪除標記。注意不要在一個空記錄集中呼叫Delete,否則會產生一個異常。
l 滾動到另一個記錄上以跳過刪除記錄。
上面提到的函式宣告為:
virtual void Edit( );throw( CDBException, CMemoryException );
virtual void AddNew( );throw( CDBException );
virtual void Delete( );throw( CDBException );
virtual BOOL Update( );throw( CDBException );
若更新失敗則函式返回FALSE,且會產生一個異常。
在對記錄集進行更改以前,程式也許要呼叫下列函式來判斷記錄集是否是可以更改的,因為如果在不能更改的記錄集中進行修改、新增或刪除將導致異常的產生。
BOOL CanUpdate( ) const; //返回TRUE表明記錄是可以修改、新增和刪除的。
BOOL CanAppend( ) const; //返回TRUE則表明可以新增記錄。
7. CRecordset類成員
資料成員
m_hstmt |
包含記錄集的ODBC語句控制代碼。型別為HSTMT |
m_nFields |
包含記錄集中的欄位資料成員數目。型別為UINT |
m_nParams |
包含記錄集中引數資料成員的數目。型別為UINT |
m_pDatabase |
包含一個指向CDatabase物件的指標,提供該指標將記錄集連線到一個數據源 |
m_strFilter |
包含一個CString,此物件指定一條結構式查詢語言(SQL)的WHERE子句。此成員可用作一個過濾器,只選擇符合某一標準的那些記錄 |
m_strSort |
包含一個CString,此物件指定一條SQLORDERBY子句。此成員可用於控制記錄的排序 |
構造
CRecordset |
構造一個CRecordset物件。應用程式的派生類必須提供一個呼叫此函式的建構函式 |
通過檢取記錄集表示的表格或執行查詢來開啟記錄集 |
|
Close |
關閉記錄集和與此記錄集相關聯的ODBCHSTMT |
記錄集屬性
CanAppend |
如果新記錄可以通過 |
AddNew |
成員函式增加到記錄集中,則該函式返回一個非零值 |
CanBookmark |
如果記錄集支援書籤則函式返回一個非零值 |
CanRestart |
如果可以呼叫Requery來再次執行記錄集的查詢,則該函式返回一個非零值 |
CanScroll |
如果應用程式可以滾動記錄,則該函式返回一個非零值 |
CanTransact |
如果資料來源支援事務,則該函式返回一個非零值 |
CanUpdate |
如果記錄集可修改(應用程式可以增加、修改或刪除記錄),則該函式返回一個非零值 |
GetODBCFieldCount |
返回記錄集中的欄位數目 |
GetRecordCount |
返回記錄集中的記錄數目 |
GetStatus |
獲取記錄集的狀態:讀取記錄的索引,以及是否已獲取到記錄的最終計數 |
GetTableName |
獲取此記錄集基於的表的名字 |
GetSQL |
獲取用於選擇記錄集的記錄的SQL字串 |
IsOpen |
如果前面已經呼叫了Open函式,則此函式返回一個非零值 |
IsBOF |
如果記錄集已經定位在第一個記錄前,則此函式返回一個非零值 |
IsEOF |
如果記錄集已經定位在最後一個記錄後,則此函式返回一個非零值 |
IsDeleted |
如果記錄集定位在一個已刪除的記錄上,則該函式返回一個非零值 |
記錄集更新操作
AddNew |
為增加新記錄做準備。呼叫Update來完成增加 |
CancelUpdate |
取消任何用AddNew或Edit操作指定的未決定的更新 |
Delete |
從記錄集中刪除當前記錄。刪除之後,應用程式必須顯式地滾動到另一個記錄 |
Edit |
為改變當前記錄作準備。呼叫Update來完成編輯 |
Update |
通過將新資料或所編輯的資料儲存到資料來源上,來完成一次AddNew或Edit操作 |
記錄集定位操作
GetBookMark |
將一個記錄的標籤值分配給該引數物件 |
Move |
將記錄集雙向定位到距離當前記錄指定數目的記錄的位置 |
MoveFirst |
定位當前記錄為記錄集中的第一個記錄。該函式首先測試IsBOF |
MoveLast |
定位當前記錄為記錄集中的最後一個記錄。該函式首先測試IsEOF |
MoveNext |
定位當前記錄為記錄集中的下一個記錄。該函式首先測試IsEOF |
MovePrev |
定位當前記錄為記錄集中的第一個記錄。該函式首先測試IsBOF |
SetAbsolutePosition |
將記錄集定位到與指定的記錄數相對應的位置 |
SetBookmark |
定位記錄集到書籤指定的位置 |
其他記錄集操作
Cancel |
取消一次非同步操作或一次來自第二執行緒的處理 |
FlushResultSet |
當使用一個預定義的查詢時,如果有另外一個結果被獲取,返回非零值 |
GetFieldValue |
返回記錄集中的一個欄位的值 |
GetODBCFieldInfo |
返回記錄集中各欄位的指定類別的資訊 |
GetRowsetSize |
返回在一次單個獲取中你要獲取的記錄數目 |
GetRowsFetched |
返回在一次獲取中實際獲取的行數 |
GetRowStatus |
返回在一次獲取中行的狀態 |
IsFieldDirty |
如果在當前記錄中的指定欄位被改變,則返回一個非零值 |
IsFieldNull |
如果當前記錄中的指定欄位是Null(沒有值),則返回非零值 |
IsFieldNullable |
如果當前記錄中的指定欄位可被設定為Null(沒有值),則返回非零值 |
RefreshRowset |
重新整理指定行的資料和狀態 |
Requery |
再次執行記錄集的查詢來重新整理所選擇的記錄 |
SetFieldDirty |
標記當前記錄中的指定欄位是被改變的 |
SetFieldNull |
設定當前記錄中的指定欄位的值為Null(沒有值) |
SetLockingMode |
將加鎖模式設定為“樂觀”加鎖(預設值)或“悲觀”加鎖。確定任何更新加鎖記錄 |
SetParamNull |
將指定的引數設定為Null(沒有值) |
SetRowsetCursorPosition |
將遊標定位在記錄集中的指定行上 |
記錄集過載函式
Check |
用來檢查從一個ODBC API函式返回的程式碼 |
CheckRowSetError |
用來處理在獲取記錄期間產生的錯誤 |
DoBulkFieldExchange |
用來將一組資料行從資料來源中交換到記錄集中。實現成組記錄交換(BulkRFX) |
DoFieldExchange |
用來在此記錄集的欄位資料成員和資料來源上對應的記錄之間交換資料(雙向)。雙向記錄欄位交換(RFX) |
GetDefaultConnect |
用來獲取預設的字串 |
GetDefaultSQL |
用來獲取要執行的預設的SQL字串 |
OnSetOptions |
用來為指定的ODBC語句設定選項 |
SetRowsetSize |
指定在一次獲取中你希望獲取的記錄數目 |
以下程式碼是Excel表中匯入資料片段:
GetDlgItemText(IDC_MFCEDITBROWSE1, m_FilePath);//獲取路徑
CDatabase db;//資料庫庫需要包含標頭檔案 #include <afxdb.h>
CString sDriver = _T("MICROSOFT EXCEL DRIVER (*.XLS)"); // 安裝Excel驅動
CString sSql;
sSql.Format(_T("DRIVER={%s};DSN='';FIRSTROWHASNAMES=1;READONLY=FALSE;CREATE_DB=\"%s\";DBQ=%s"), sDriver, m_FilePath, m_FilePath);
if (!db.OpenEx(sSql, CDatabase::noOdbcDialog))//連線資料來源DJB.xls
{
MessageBox(_T("開啟EXCEL檔案失敗!"), _T("錯誤"));
return;
}
//開啟EXCEL表
CRecordset pset(&db);
m_list.DeleteAllItems();
/* sSql = "SELECT 學號,姓名,成績 "
"FROM EXCELDEMO"; */
// "ORDER BY 姓名";
//sSql.Format(_T("SELECT 學號,姓名,性別,年級,班級,學校,身高,體重 FROM TEST"));
sSql.Format(_T("SELECT 序號,學號,姓名,入學年份 FROM [Sheet1$]"));
//執行查詢語句
pset.Open(CRecordset::forwardOnly, sSql, CRecordset::readOnly);
while (!pset.IsEOF())
{
pset.GetFieldValue(_T("序號"), arr[0]);//前面欄位必須與表中的相同,否則出錯。
pset.GetFieldValue(_T("學號"), arr[1]);
pset.GetFieldValue(_T("姓名"), arr[2]);
pset.GetFieldValue(_T("入學年份"), arr[3]);
//所有學生姓名儲存到vertor陣列
stu_name.push_back(arr[2]);
arr[0] = arr[0].Left(arr[0].GetLength() - 2);
arr[3] = arr[3].Left(arr[3].GetLength() - 2);
count = m_list.GetItemCount();//獲取行的數量
m_list.InsertItem(count, arr[0]);//插入行
m_list.SetItemText(count, 1, arr[1]);
m_list.SetItemText(count, 2, arr[2]);
m_list.SetItemText(count, 3, arr[3]);
m_list.SetItemText(count, 4, arr[4]);
pset.MoveNext();
}
db.Close();