在MySQL數(shù)據(jù)庫(kù)中使用C執(zhí)行SQL語(yǔ)句的方法
更新時(shí)間:2012年10月15日 02:23:28 作者:
與PostgreSQL相似,可使用許多不同的語(yǔ)言來(lái)訪問(wèn)MySQL,包括C、C++、Java和Perl。從Professional Linux Programming中第5章有關(guān)MySQL的下列章節(jié)中,Neil Matthew和Richard Stones使用詳盡的MySQL C接口向我們介紹了如何在MySQL數(shù)據(jù)庫(kù)中執(zhí)行SQL語(yǔ)句。
他們將討論返回?cái)?shù)據(jù)的語(yǔ)句,例如INSERT以及不返回?cái)?shù)據(jù)的語(yǔ)句,例如UPDATE和DELETE。然后,他們將編寫從數(shù)據(jù)庫(kù)檢索數(shù)據(jù)的簡(jiǎn)單程序
執(zhí)行SQL語(yǔ)句
現(xiàn)在,我們已經(jīng)有了一個(gè)連接,并且知道如何處理錯(cuò)誤,是時(shí)候討論使用我們的數(shù)據(jù)庫(kù)來(lái)作一些實(shí)際工作了。執(zhí)行所有類型的SQL的主關(guān)鍵字是mysql_query:
int mysql_query(MYSQL *connection, const char *query)
正如您所見(jiàn),它非常簡(jiǎn)單。它取一個(gè)指向連接結(jié)構(gòu)的指針和包含要執(zhí)行的SQL的文本字符串;與命令行工具不同,將不使用結(jié)束分號(hào)。成功之后,返回0。在需要包含二進(jìn)制數(shù)據(jù)的特殊情況下,可以使用相關(guān)的函數(shù),mysql_real_query。雖然出于本章的目的,我們僅需要討論mysql_query。
不返回?cái)?shù)據(jù)的SQL語(yǔ)句
我們將先討論UPDATE、DELETE和INSERT語(yǔ)句。因?yàn)樗鼈儾环祷財(cái)?shù)據(jù),所以更易于使用。
這里我們將介紹的另一個(gè)重要函數(shù)是檢查受影響的行數(shù)的函數(shù):
my_ulonglong mysql_affected_rows(MYSQL *connection);
可能關(guān)于這一函數(shù)的最顯而易見(jiàn)的事就是其非同尋常的返回結(jié)果。由于可移植性原因,這是一個(gè)特殊的無(wú)符號(hào)類型。為了在printf中使用,建議將其強(qiáng)制轉(zhuǎn)換成使用%lu格式規(guī)范的無(wú)符號(hào)長(zhǎng)整數(shù)。這個(gè)函數(shù)返回受以前的UPDATE、INSERT或DELETE查詢影響的行數(shù),這些查詢是使用mysql_query執(zhí)行的。
通常對(duì)于mysql_函數(shù),返回碼0表示沒(méi)有行受影響;正數(shù)表示實(shí)際結(jié)果,通常是受影響的行數(shù)。
如前所述,當(dāng)使用mysql_affected_rows時(shí)可能出現(xiàn)未期望的結(jié)果。讓我們先討論受INSERT語(yǔ)句影響的行數(shù),它將按預(yù)期進(jìn)行操作。將下列代碼添加到程序 connect2.c 中,并且稱其為insert1.c:
#include
#include
#include "mysql.h"
int main(int argc, char *argv[]) {
MYSQL my_connection;
int res;
mysql_init(&my_connection);
if (mysql_real_connect(&my_connection, "localhost",
"rick", "bar", "rick", 0, NULL, 0)) {
printf("Connection success\n");
res = mysql_query(&my_connection,
"INSERT INTO children(fname,age),
VALUES('Ann',3)");
if (!res) {
printf("Inserted %lu rows\n",
(unsigned long)mysql_affected_rows(&my_connection));
} else {
fprintf(stderr, "Insert error %d: s\n",mysql_errno ,
(&my_connection),
mysql_error(&my_connection));
}
mysql_close(&my_connection);
} else {
fprintf(stderr, "Connection failed\n");
if (mysql_errno(&my_connection)) {
fprintf(stderr, "Connection error %d: %s\n",
mysql_errno(&my_connection),
mysql_error(&my_connection));
}
}
return EXIT_SUCCESS;
}
正如預(yù)期,插入的行數(shù)為1。
現(xiàn)在,我們更改代碼,所以 'insert' 部分被替換成:
mysql_errno(&my_connection), mysql_error(&my_connection));
}
}
res = mysql_query(&my_connection, "UPDATE children SET AGE = 4
WHERE fname = 'Ann'");
if (!res) {
printf("Updated %lu rows\n",
(unsigned long)mysql_affected_rows(&my_connection));
} else {
fprintf(stderr, "Update error %d: %s\n",
mysql_errno(&my_connection),
mysql_error(&my_connection));
}
現(xiàn)在假設(shè)子表中有的數(shù)據(jù),如下:
如果我們執(zhí)行update1,希望報(bào)告的受影響行數(shù)為4,但是實(shí)際上程序報(bào)告2,因?yàn)樗鼉H必須更改2行,雖然WHERE子句標(biāo)識(shí)了4行。如果想讓mysql_affected_rows報(bào)告的結(jié)果為4這可能是熟悉其它數(shù)據(jù)庫(kù)的人所期望的),則需要記住將CLIENT_FOUND_ROWS標(biāo)志傳遞到mysql_real_connect,在 update2.c中的程序如下:
if (mysql_real_connect(&my_connection, "localhost",
"rick", "bar", "rick", 0, NULL, CLIENT_FOUND_ROWS)) {
如果我們?cè)跀?shù)據(jù)庫(kù)中復(fù)位數(shù)據(jù),然后運(yùn)行帶有這種修改的程序,則它報(bào)告的行數(shù)為4。
函數(shù)mysql_affected_rows還有最后一個(gè)奇怪之處,它發(fā)生在從數(shù)據(jù)庫(kù)中刪除數(shù)據(jù)時(shí)。如果使用WHERE子句,則mysql_affected_rows將按預(yù)期返回刪除行數(shù)。但是,如果沒(méi)有WHERE子句,則刪除所有行,報(bào)告受影響的行數(shù)卻為0。這是因?yàn)橛捎谛试騼?yōu)化刪除整個(gè)表。這種行為不受CLIENT_FOUND_ROWS選項(xiàng)標(biāo)志的影響。
返回?cái)?shù)據(jù)的語(yǔ)句
現(xiàn)在是時(shí)候討論SQL的最普遍用法了,從數(shù)據(jù)庫(kù)檢索數(shù)據(jù)的SELECT語(yǔ)句。
MySQL 還支持返回結(jié)果的SHOW、DESCRIBE和EXPLAIN SQL語(yǔ)句,但是這里不考慮它們。按慣例,手冊(cè)中包含這些語(yǔ)句的說(shuō)明。
您將會(huì)從PostgreSQL章記起,可以從PQexec中的SQL SELECT 語(yǔ)句檢索數(shù)據(jù),這里馬上獲取所有數(shù)據(jù),或者使用游標(biāo)從數(shù)據(jù)庫(kù)中逐行檢索數(shù)據(jù),以便搞定大數(shù)據(jù)。
由于完全相同的原因,MySQL的檢索方法幾乎完全相同,雖然它實(shí)際上不用游標(biāo)的形式描述逐行檢索。但是,它提供了縮小這兩種方法間差異的API,如果需要,它通常使兩種方法的互換更加容易。
通常,從MySQL數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)有4個(gè)階段:
發(fā)出查詢
檢索數(shù)據(jù)
處理數(shù)據(jù)
執(zhí)行所需的任何整理
象以前一樣,我們使用mysql_query發(fā)出查詢。數(shù)據(jù)檢索是使用mysql_store_result或mysql_use_result完成的,這取決于想如何檢索數(shù)據(jù),隨后使用mysql_fetch_row調(diào)用序列來(lái)處理數(shù)據(jù)。最后,必須調(diào)用mysql_free_result以允許MySQL執(zhí)行任何所需的整理。
全部立即數(shù)據(jù)檢索的函數(shù)
可以從SELECT語(yǔ)句(或其他返回?cái)?shù)據(jù)的語(yǔ)句)中檢索完所有數(shù)據(jù),在單一調(diào)用中,使用mysql_store_result:
MYSQL_RES *mysql_store_result(MYSQL *connection);
必須在mysql_query檢索數(shù)據(jù)后才能調(diào)用這個(gè)函數(shù),以在結(jié)果集中存儲(chǔ)該數(shù)據(jù)。這個(gè)函數(shù)從服務(wù)器中檢索所有數(shù)據(jù)并立即將它存儲(chǔ)在客戶機(jī)中。它返回一個(gè)指向以前我們從未遇到過(guò)的結(jié)構(gòu)(結(jié)果集結(jié)構(gòu))的指針。如果語(yǔ)句失敗,則返回NULL。
使用等價(jià)的PostgreSQL時(shí),應(yīng)該知道返回NULL意味著已經(jīng)發(fā)生了錯(cuò)誤,并且這與未檢索到數(shù)據(jù)的情況不同。即使,返回值不是NULL,也不意味著當(dāng)前有數(shù)據(jù)要處理。
如果未返回NULL,則可以調(diào)用mysql_num_rows并且檢索實(shí)際返回的行數(shù),它當(dāng)然可能是0。
my_ulonglong mysql_num_rows(MYSQL_RES *result);
它從mysql_store_result取得返回的結(jié)果結(jié)構(gòu),并且在該結(jié)果集中返回行數(shù),行數(shù)可能為0。如果mysql_store_result成功,則mysql_num_rows也總是成功的。
這種mysql_store_result和mysql_num_rows的組合是檢索數(shù)據(jù)的一種簡(jiǎn)便并且直接的方法。一旦mysql_store_result成功返回,則所有查詢數(shù)據(jù)都已經(jīng)存儲(chǔ)在客戶機(jī)上并且我們知道可以從結(jié)果結(jié)構(gòu)中檢索它,而不用擔(dān)心會(huì)發(fā)生數(shù)據(jù)庫(kù)或網(wǎng)絡(luò)錯(cuò)誤,因?yàn)閷?duì)于程序所有數(shù)據(jù)都是本地的。還可以立即發(fā)現(xiàn)返回的行數(shù),它可以使編碼更簡(jiǎn)便。如前所述,它將所有結(jié)果立即地發(fā)送回客戶機(jī)。對(duì)于大結(jié)果集,它可能耗費(fèi)大量的服務(wù)器、網(wǎng)絡(luò)和客戶機(jī)資源。由于這些原因,使用更大的數(shù)據(jù)集時(shí),最好僅檢索需要的數(shù)據(jù)。不久,我們將討論如何使用mysql_use_result函數(shù)來(lái)完成該操作。
一旦檢索了數(shù)據(jù),則可以使用mysql_fetch_row來(lái)檢索它,并且使用mysql_data_seek、mysql_row_seek、mysql_row_tell操作結(jié)果集。在開始檢索數(shù)據(jù)階段之前,讓我們先討論一下這些函數(shù)。
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
這個(gè)函數(shù)采用從存儲(chǔ)結(jié)果中獲取的結(jié)果結(jié)構(gòu),并且從中檢索單一行,在行結(jié)構(gòu)中返回分配給您的數(shù)據(jù)。當(dāng)沒(méi)有更多數(shù)據(jù)或者發(fā)生錯(cuò)誤時(shí),返回NULL。稍后,我們將回來(lái)處理這一行中的數(shù)據(jù)。
void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);
這個(gè)函數(shù)允許您進(jìn)入結(jié)果集,設(shè)置將由下一個(gè)獲取操作返回的行。offset是行號(hào),它必須在從0到結(jié)果集中的行數(shù)減 1 的范圍內(nèi)。傳遞0將導(dǎo)致在下一次調(diào)用mysql_fetch_row時(shí)返回第一行。
MYSQL_ROW_OFFEST mysql_row_tell(MYSQL_RES *result);
這個(gè)函數(shù)返回一個(gè)偏移值,它表示結(jié)果集中的當(dāng)前位置。它不是行號(hào),不能將它用于mysql_data_seek。但是,可將它用于:
MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset);
它移動(dòng)結(jié)果集中的當(dāng)前位置,并返回以前的位置。
有時(shí),這一對(duì)函數(shù)對(duì)于在結(jié)果集中的已知點(diǎn)之間跳轉(zhuǎn)很有用。請(qǐng)注意,不要將row tell和row seek使用的偏移值與data_seek使用的行號(hào)混淆。這些是不可交換的,結(jié)果將是您所希望看到的。
void mysql_free_result(MYSQL_RES *result);
完成結(jié)果集時(shí), 必須總是調(diào)用這個(gè)函數(shù),以允許MySQL庫(kù)整理分配給它的對(duì)象。
檢索數(shù)據(jù)
現(xiàn)在開始編寫從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)的第一個(gè)程序。我們將選擇所有年齡大于5的行的內(nèi)容。不幸的是我們還不知道如何處理這個(gè)數(shù)據(jù),所以我們能做的只有循環(huán)檢索它。這便是 select1.c:
#include
#include
#include "mysql.h"
MYSQL my_connection;
MYSQL_RES *res_ptr;
MYSQL_ROW sqlrow;
int main(int argc, char *argv[]) {
int res;
mysql_init(&my_connection);
if (mysql_real_connect(&my_connection, "localhost", "rick",
"bar", "rick", 0, NULL, 0)) {
printf("Connection success\n");
res = mysql_query(&my_connection, "SELECT childno, fname,
age FROM children WHERE age > 5");
if (res) {
printf("SELECT error: %s\n", mysql_error(&my_connection));
} else {
res_ptr = mysql_store_result(&my_connection);
if (res_ptr) {
printf("Retrieved %luows\n",(unsignedlong)mysql_num_rows(res_ptr));
while ((sqlrow = mysql_fetch_row(res_ptr))) {
printf("Fetched data...\n");
}
if (mysql_errno(&my_connection)) {
fprintf(stderr, "Retrive error: s\n",mysql_error(&my_connection));
}
}
mysql_free_result(res_ptr);
}
mysql_close(&my_connection);
} else {
fprintf(stderr, "Connection failed\n");
if (mysql_errno(&my_connection)) {
fprintf(stderr, "Connection error %d: %s\n",
mysql_errno(&my_connection),mysql_error(&my_connection));
}
}
return EXIT_SUCCESS;
}
檢索結(jié)果集并循環(huán)通過(guò)已檢索的數(shù)據(jù)的重要部分都已突出顯示。
一次檢索一行數(shù)據(jù)
要按需要逐行檢索數(shù)據(jù),而不是立即獲取全部數(shù)據(jù)并將它存儲(chǔ)在客戶機(jī)中,可以將mysql_store_result調(diào)用替換成 mysql_use_result:
MYSQL_RES *mysql_use_result(MYSQL *connection);
這個(gè)函數(shù)還取得一個(gè)連接對(duì)象并返回結(jié)果結(jié)合指針,或者出錯(cuò)時(shí)返回NULL。與mysql_store_result相似,它返回指向結(jié)果集對(duì)象的指針;關(guān)鍵的不同點(diǎn)在于返回時(shí),實(shí)際上沒(méi)有將任何數(shù)據(jù)檢索到結(jié)果集,只是初始化結(jié)果集以準(zhǔn)備好檢索數(shù)據(jù)。
參考資料
您可以參閱本文在developerWorks全球站點(diǎn)上的英文原文.
本文章取自Wrox Press Ltd出版的Professional Linux一書的第5章。
關(guān)于作者
Rick Stones是一位系統(tǒng)設(shè)計(jì)師,他在一家大型泛歐制藥分銷和分配公司的IT部門工作。從1985年開始,他一直在使用各種形式的 UNIX,并且發(fā)現(xiàn)帶有早期 .99 CD-ROM發(fā)行版的Linux。他用各種語(yǔ)言編寫UNIX、Linux和其它平臺(tái)的軟件,同時(shí)還安裝并管理幾臺(tái)Linux服務(wù)器。在非常有限的業(yè)余時(shí)間,他努力提高他的鋼琴演奏技巧。
從大學(xué)時(shí)代開始接觸C和UNIX V6時(shí)起,Neil Matthew對(duì)于UNIX和Linux已經(jīng)超過(guò)20年的經(jīng)驗(yàn)。從那時(shí)起他就在IT業(yè)工作,主要從事通信軟件的開發(fā),一直保持對(duì)于深?yuàn)W的編程語(yǔ)言和開發(fā)技術(shù)的熱情?,F(xiàn)在,他作為系統(tǒng)設(shè)計(jì)師,對(duì)技術(shù)戰(zhàn)略和QA提出建議。他熱心于在公司企業(yè)內(nèi)建立Linux商業(yè)案例。業(yè)余時(shí)間,寫作或騎馬為樂(lè),Neil努力勸說(shuō)他的妻子和兩個(gè)孩子與他一起在鄉(xiāng)間散步。Neil參與編寫了Wrox Press發(fā)行的好幾本書,最著名的是共同著作了Beginning Linux Programming和Professional Linux Programming。
執(zhí)行SQL語(yǔ)句
現(xiàn)在,我們已經(jīng)有了一個(gè)連接,并且知道如何處理錯(cuò)誤,是時(shí)候討論使用我們的數(shù)據(jù)庫(kù)來(lái)作一些實(shí)際工作了。執(zhí)行所有類型的SQL的主關(guān)鍵字是mysql_query:
int mysql_query(MYSQL *connection, const char *query)
正如您所見(jiàn),它非常簡(jiǎn)單。它取一個(gè)指向連接結(jié)構(gòu)的指針和包含要執(zhí)行的SQL的文本字符串;與命令行工具不同,將不使用結(jié)束分號(hào)。成功之后,返回0。在需要包含二進(jìn)制數(shù)據(jù)的特殊情況下,可以使用相關(guān)的函數(shù),mysql_real_query。雖然出于本章的目的,我們僅需要討論mysql_query。
不返回?cái)?shù)據(jù)的SQL語(yǔ)句
我們將先討論UPDATE、DELETE和INSERT語(yǔ)句。因?yàn)樗鼈儾环祷財(cái)?shù)據(jù),所以更易于使用。
這里我們將介紹的另一個(gè)重要函數(shù)是檢查受影響的行數(shù)的函數(shù):
my_ulonglong mysql_affected_rows(MYSQL *connection);
可能關(guān)于這一函數(shù)的最顯而易見(jiàn)的事就是其非同尋常的返回結(jié)果。由于可移植性原因,這是一個(gè)特殊的無(wú)符號(hào)類型。為了在printf中使用,建議將其強(qiáng)制轉(zhuǎn)換成使用%lu格式規(guī)范的無(wú)符號(hào)長(zhǎng)整數(shù)。這個(gè)函數(shù)返回受以前的UPDATE、INSERT或DELETE查詢影響的行數(shù),這些查詢是使用mysql_query執(zhí)行的。
通常對(duì)于mysql_函數(shù),返回碼0表示沒(méi)有行受影響;正數(shù)表示實(shí)際結(jié)果,通常是受影響的行數(shù)。
如前所述,當(dāng)使用mysql_affected_rows時(shí)可能出現(xiàn)未期望的結(jié)果。讓我們先討論受INSERT語(yǔ)句影響的行數(shù),它將按預(yù)期進(jìn)行操作。將下列代碼添加到程序 connect2.c 中,并且稱其為insert1.c:
復(fù)制代碼 代碼如下:
#include
#include
#include "mysql.h"
int main(int argc, char *argv[]) {
MYSQL my_connection;
int res;
mysql_init(&my_connection);
if (mysql_real_connect(&my_connection, "localhost",
"rick", "bar", "rick", 0, NULL, 0)) {
printf("Connection success\n");
res = mysql_query(&my_connection,
"INSERT INTO children(fname,age),
VALUES('Ann',3)");
if (!res) {
printf("Inserted %lu rows\n",
(unsigned long)mysql_affected_rows(&my_connection));
} else {
fprintf(stderr, "Insert error %d: s\n",mysql_errno ,
(&my_connection),
mysql_error(&my_connection));
}
mysql_close(&my_connection);
} else {
fprintf(stderr, "Connection failed\n");
if (mysql_errno(&my_connection)) {
fprintf(stderr, "Connection error %d: %s\n",
mysql_errno(&my_connection),
mysql_error(&my_connection));
}
}
return EXIT_SUCCESS;
}
正如預(yù)期,插入的行數(shù)為1。
現(xiàn)在,我們更改代碼,所以 'insert' 部分被替換成:
復(fù)制代碼 代碼如下:
mysql_errno(&my_connection), mysql_error(&my_connection));
}
}
res = mysql_query(&my_connection, "UPDATE children SET AGE = 4
WHERE fname = 'Ann'");
if (!res) {
printf("Updated %lu rows\n",
(unsigned long)mysql_affected_rows(&my_connection));
} else {
fprintf(stderr, "Update error %d: %s\n",
mysql_errno(&my_connection),
mysql_error(&my_connection));
}
現(xiàn)在假設(shè)子表中有的數(shù)據(jù),如下:
childno | fname | age |
1
2 3 4 5 6 7 8 9 10 11 |
Jenny
Andrew Gavin Duncan Emma Alex Adrian Ann Ann Ann Ann |
14
10 4 2 0 11 5 3 4 3 4 |
復(fù)制代碼 代碼如下:
if (mysql_real_connect(&my_connection, "localhost",
"rick", "bar", "rick", 0, NULL, CLIENT_FOUND_ROWS)) {
如果我們?cè)跀?shù)據(jù)庫(kù)中復(fù)位數(shù)據(jù),然后運(yùn)行帶有這種修改的程序,則它報(bào)告的行數(shù)為4。
函數(shù)mysql_affected_rows還有最后一個(gè)奇怪之處,它發(fā)生在從數(shù)據(jù)庫(kù)中刪除數(shù)據(jù)時(shí)。如果使用WHERE子句,則mysql_affected_rows將按預(yù)期返回刪除行數(shù)。但是,如果沒(méi)有WHERE子句,則刪除所有行,報(bào)告受影響的行數(shù)卻為0。這是因?yàn)橛捎谛试騼?yōu)化刪除整個(gè)表。這種行為不受CLIENT_FOUND_ROWS選項(xiàng)標(biāo)志的影響。
返回?cái)?shù)據(jù)的語(yǔ)句
現(xiàn)在是時(shí)候討論SQL的最普遍用法了,從數(shù)據(jù)庫(kù)檢索數(shù)據(jù)的SELECT語(yǔ)句。
MySQL 還支持返回結(jié)果的SHOW、DESCRIBE和EXPLAIN SQL語(yǔ)句,但是這里不考慮它們。按慣例,手冊(cè)中包含這些語(yǔ)句的說(shuō)明。
您將會(huì)從PostgreSQL章記起,可以從PQexec中的SQL SELECT 語(yǔ)句檢索數(shù)據(jù),這里馬上獲取所有數(shù)據(jù),或者使用游標(biāo)從數(shù)據(jù)庫(kù)中逐行檢索數(shù)據(jù),以便搞定大數(shù)據(jù)。
由于完全相同的原因,MySQL的檢索方法幾乎完全相同,雖然它實(shí)際上不用游標(biāo)的形式描述逐行檢索。但是,它提供了縮小這兩種方法間差異的API,如果需要,它通常使兩種方法的互換更加容易。
通常,從MySQL數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)有4個(gè)階段:
發(fā)出查詢
檢索數(shù)據(jù)
處理數(shù)據(jù)
執(zhí)行所需的任何整理
象以前一樣,我們使用mysql_query發(fā)出查詢。數(shù)據(jù)檢索是使用mysql_store_result或mysql_use_result完成的,這取決于想如何檢索數(shù)據(jù),隨后使用mysql_fetch_row調(diào)用序列來(lái)處理數(shù)據(jù)。最后,必須調(diào)用mysql_free_result以允許MySQL執(zhí)行任何所需的整理。
全部立即數(shù)據(jù)檢索的函數(shù)
可以從SELECT語(yǔ)句(或其他返回?cái)?shù)據(jù)的語(yǔ)句)中檢索完所有數(shù)據(jù),在單一調(diào)用中,使用mysql_store_result:
復(fù)制代碼 代碼如下:
MYSQL_RES *mysql_store_result(MYSQL *connection);
必須在mysql_query檢索數(shù)據(jù)后才能調(diào)用這個(gè)函數(shù),以在結(jié)果集中存儲(chǔ)該數(shù)據(jù)。這個(gè)函數(shù)從服務(wù)器中檢索所有數(shù)據(jù)并立即將它存儲(chǔ)在客戶機(jī)中。它返回一個(gè)指向以前我們從未遇到過(guò)的結(jié)構(gòu)(結(jié)果集結(jié)構(gòu))的指針。如果語(yǔ)句失敗,則返回NULL。
使用等價(jià)的PostgreSQL時(shí),應(yīng)該知道返回NULL意味著已經(jīng)發(fā)生了錯(cuò)誤,并且這與未檢索到數(shù)據(jù)的情況不同。即使,返回值不是NULL,也不意味著當(dāng)前有數(shù)據(jù)要處理。
如果未返回NULL,則可以調(diào)用mysql_num_rows并且檢索實(shí)際返回的行數(shù),它當(dāng)然可能是0。
復(fù)制代碼 代碼如下:
my_ulonglong mysql_num_rows(MYSQL_RES *result);
它從mysql_store_result取得返回的結(jié)果結(jié)構(gòu),并且在該結(jié)果集中返回行數(shù),行數(shù)可能為0。如果mysql_store_result成功,則mysql_num_rows也總是成功的。
這種mysql_store_result和mysql_num_rows的組合是檢索數(shù)據(jù)的一種簡(jiǎn)便并且直接的方法。一旦mysql_store_result成功返回,則所有查詢數(shù)據(jù)都已經(jīng)存儲(chǔ)在客戶機(jī)上并且我們知道可以從結(jié)果結(jié)構(gòu)中檢索它,而不用擔(dān)心會(huì)發(fā)生數(shù)據(jù)庫(kù)或網(wǎng)絡(luò)錯(cuò)誤,因?yàn)閷?duì)于程序所有數(shù)據(jù)都是本地的。還可以立即發(fā)現(xiàn)返回的行數(shù),它可以使編碼更簡(jiǎn)便。如前所述,它將所有結(jié)果立即地發(fā)送回客戶機(jī)。對(duì)于大結(jié)果集,它可能耗費(fèi)大量的服務(wù)器、網(wǎng)絡(luò)和客戶機(jī)資源。由于這些原因,使用更大的數(shù)據(jù)集時(shí),最好僅檢索需要的數(shù)據(jù)。不久,我們將討論如何使用mysql_use_result函數(shù)來(lái)完成該操作。
一旦檢索了數(shù)據(jù),則可以使用mysql_fetch_row來(lái)檢索它,并且使用mysql_data_seek、mysql_row_seek、mysql_row_tell操作結(jié)果集。在開始檢索數(shù)據(jù)階段之前,讓我們先討論一下這些函數(shù)。
復(fù)制代碼 代碼如下:
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
這個(gè)函數(shù)采用從存儲(chǔ)結(jié)果中獲取的結(jié)果結(jié)構(gòu),并且從中檢索單一行,在行結(jié)構(gòu)中返回分配給您的數(shù)據(jù)。當(dāng)沒(méi)有更多數(shù)據(jù)或者發(fā)生錯(cuò)誤時(shí),返回NULL。稍后,我們將回來(lái)處理這一行中的數(shù)據(jù)。
復(fù)制代碼 代碼如下:
void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);
這個(gè)函數(shù)允許您進(jìn)入結(jié)果集,設(shè)置將由下一個(gè)獲取操作返回的行。offset是行號(hào),它必須在從0到結(jié)果集中的行數(shù)減 1 的范圍內(nèi)。傳遞0將導(dǎo)致在下一次調(diào)用mysql_fetch_row時(shí)返回第一行。
復(fù)制代碼 代碼如下:
MYSQL_ROW_OFFEST mysql_row_tell(MYSQL_RES *result);
這個(gè)函數(shù)返回一個(gè)偏移值,它表示結(jié)果集中的當(dāng)前位置。它不是行號(hào),不能將它用于mysql_data_seek。但是,可將它用于:
復(fù)制代碼 代碼如下:
MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset);
它移動(dòng)結(jié)果集中的當(dāng)前位置,并返回以前的位置。
有時(shí),這一對(duì)函數(shù)對(duì)于在結(jié)果集中的已知點(diǎn)之間跳轉(zhuǎn)很有用。請(qǐng)注意,不要將row tell和row seek使用的偏移值與data_seek使用的行號(hào)混淆。這些是不可交換的,結(jié)果將是您所希望看到的。
復(fù)制代碼 代碼如下:
void mysql_free_result(MYSQL_RES *result);
完成結(jié)果集時(shí), 必須總是調(diào)用這個(gè)函數(shù),以允許MySQL庫(kù)整理分配給它的對(duì)象。
檢索數(shù)據(jù)
現(xiàn)在開始編寫從數(shù)據(jù)庫(kù)中檢索數(shù)據(jù)的第一個(gè)程序。我們將選擇所有年齡大于5的行的內(nèi)容。不幸的是我們還不知道如何處理這個(gè)數(shù)據(jù),所以我們能做的只有循環(huán)檢索它。這便是 select1.c:
復(fù)制代碼 代碼如下:
#include
#include
#include "mysql.h"
MYSQL my_connection;
MYSQL_RES *res_ptr;
MYSQL_ROW sqlrow;
int main(int argc, char *argv[]) {
int res;
mysql_init(&my_connection);
if (mysql_real_connect(&my_connection, "localhost", "rick",
"bar", "rick", 0, NULL, 0)) {
printf("Connection success\n");
res = mysql_query(&my_connection, "SELECT childno, fname,
age FROM children WHERE age > 5");
if (res) {
printf("SELECT error: %s\n", mysql_error(&my_connection));
} else {
res_ptr = mysql_store_result(&my_connection);
if (res_ptr) {
printf("Retrieved %luows\n",(unsignedlong)mysql_num_rows(res_ptr));
while ((sqlrow = mysql_fetch_row(res_ptr))) {
printf("Fetched data...\n");
}
if (mysql_errno(&my_connection)) {
fprintf(stderr, "Retrive error: s\n",mysql_error(&my_connection));
}
}
mysql_free_result(res_ptr);
}
mysql_close(&my_connection);
} else {
fprintf(stderr, "Connection failed\n");
if (mysql_errno(&my_connection)) {
fprintf(stderr, "Connection error %d: %s\n",
mysql_errno(&my_connection),mysql_error(&my_connection));
}
}
return EXIT_SUCCESS;
}
檢索結(jié)果集并循環(huán)通過(guò)已檢索的數(shù)據(jù)的重要部分都已突出顯示。
一次檢索一行數(shù)據(jù)
要按需要逐行檢索數(shù)據(jù),而不是立即獲取全部數(shù)據(jù)并將它存儲(chǔ)在客戶機(jī)中,可以將mysql_store_result調(diào)用替換成 mysql_use_result:
復(fù)制代碼 代碼如下:
MYSQL_RES *mysql_use_result(MYSQL *connection);
這個(gè)函數(shù)還取得一個(gè)連接對(duì)象并返回結(jié)果結(jié)合指針,或者出錯(cuò)時(shí)返回NULL。與mysql_store_result相似,它返回指向結(jié)果集對(duì)象的指針;關(guān)鍵的不同點(diǎn)在于返回時(shí),實(shí)際上沒(méi)有將任何數(shù)據(jù)檢索到結(jié)果集,只是初始化結(jié)果集以準(zhǔn)備好檢索數(shù)據(jù)。
參考資料
您可以參閱本文在developerWorks全球站點(diǎn)上的英文原文.
本文章取自Wrox Press Ltd出版的Professional Linux一書的第5章。
關(guān)于作者
Rick Stones是一位系統(tǒng)設(shè)計(jì)師,他在一家大型泛歐制藥分銷和分配公司的IT部門工作。從1985年開始,他一直在使用各種形式的 UNIX,并且發(fā)現(xiàn)帶有早期 .99 CD-ROM發(fā)行版的Linux。他用各種語(yǔ)言編寫UNIX、Linux和其它平臺(tái)的軟件,同時(shí)還安裝并管理幾臺(tái)Linux服務(wù)器。在非常有限的業(yè)余時(shí)間,他努力提高他的鋼琴演奏技巧。
從大學(xué)時(shí)代開始接觸C和UNIX V6時(shí)起,Neil Matthew對(duì)于UNIX和Linux已經(jīng)超過(guò)20年的經(jīng)驗(yàn)。從那時(shí)起他就在IT業(yè)工作,主要從事通信軟件的開發(fā),一直保持對(duì)于深?yuàn)W的編程語(yǔ)言和開發(fā)技術(shù)的熱情?,F(xiàn)在,他作為系統(tǒng)設(shè)計(jì)師,對(duì)技術(shù)戰(zhàn)略和QA提出建議。他熱心于在公司企業(yè)內(nèi)建立Linux商業(yè)案例。業(yè)余時(shí)間,寫作或騎馬為樂(lè),Neil努力勸說(shuō)他的妻子和兩個(gè)孩子與他一起在鄉(xiāng)間散步。Neil參與編寫了Wrox Press發(fā)行的好幾本書,最著名的是共同著作了Beginning Linux Programming和Professional Linux Programming。
您可能感興趣的文章:
- 六條比較有用的MySQL數(shù)據(jù)庫(kù)操作的SQL語(yǔ)句小結(jié)
- MySQl數(shù)據(jù)庫(kù)必知必會(huì)sql語(yǔ)句(加強(qiáng)版)
- MySql數(shù)據(jù)庫(kù)之a(chǎn)lter表的SQL語(yǔ)句集合
- Mysql數(shù)據(jù)庫(kù)之sql基本語(yǔ)句小結(jié)
- MySQL5.7.14下載安裝圖文教程及MySQL數(shù)據(jù)庫(kù)語(yǔ)句入門大全
- 詳解MySQL數(shù)據(jù)庫(kù)insert和update語(yǔ)句
- 優(yōu)化MySQL數(shù)據(jù)庫(kù)中的查詢語(yǔ)句詳解
- mysql數(shù)據(jù)庫(kù)重命名語(yǔ)句分享
- MySQL數(shù)據(jù)庫(kù)INSERT、UPDATE、DELETE以及REPLACE語(yǔ)句的用法詳解
- Mysql數(shù)據(jù)庫(kù)之常用sql語(yǔ)句進(jìn)階與總結(jié)
相關(guān)文章
mysql字符集和數(shù)據(jù)庫(kù)引擎修改方法分享
使用虛擬主機(jī)空間上的phpmyadmin操作數(shù)據(jù)庫(kù)的時(shí)候,如果看到phpmyadmin首頁(yè)上顯示的MySQL 字符集為cp1252 West European (latin1),當(dāng)我們導(dǎo)入數(shù)據(jù)時(shí)就會(huì)出現(xiàn)亂碼2012-02-02MySQL中使用SQL語(yǔ)句對(duì)字段進(jìn)行重命名
MySQL中,如何使用SQL語(yǔ)句來(lái)對(duì)表中某一個(gè)字段進(jìn)行重命名呢?我們將使用alter table 這一SQL語(yǔ)句,需要的朋友可以參考下2016-04-04基于Mysql+JavaSwing的超市商品管理系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)
本項(xiàng)目是使用Java swing開發(fā),可實(shí)現(xiàn)超市管理系統(tǒng)商品列表信息查詢、添加商品信息和修改商品管理以及刪除商品信息和安裝商品信息查詢等功能。界面設(shè)計(jì)和功能比較簡(jiǎn)單基礎(chǔ)、適合作為Java課設(shè)設(shè)計(jì)以及學(xué)習(xí)技術(shù)使用,需要的朋友可以參考一下2021-09-09