在MySQL資料庫中使用C執行SQL語句的方法

來源:互聯網
上載者:User

他們將討論返回資料的語句,例如INSERT以及不返回資料的語句,例如UPDATE和DELETE。然後,他們將編寫從資料庫檢索資料的簡單程式

執行SQL語句

現在,我們已經有了一個串連,並且知道如何處理錯誤,是時候討論使用我們的資料庫來作一些實際工作了。執行所有類型的SQL的主關鍵字是mysql_query:

int mysql_query(MYSQL *connection, const char *query)

正如您所見,它非常簡單。它取一個指向串連結構的指標和包含要執行的SQL的文本字串;與命令列工具不同,將不使用結束分號。成功之後,返回0。在需要包含位元據的特殊情況下,可以使用相關的函數,mysql_real_query。雖然出於本章的目的,我們僅需要討論mysql_query。
不返回資料的SQL語句

我們將先討論UPDATE、DELETE和INSERT語句。因為它們不返回資料,所以更便於使用。
這裡我們將介紹的另一個重要函數是檢查受影響的行數的函數:

my_ulonglong mysql_affected_rows(MYSQL *connection);

可能關於這一函數的最顯而易見的事就是其非同尋常的返回結果。由於可移植性原因,這是一個特殊的無符號類型。為了在printf中使用,建議將其強制轉換成使用%lu格式規範的無符號長整數。這個函數返回受以前的UPDATE、INSERT或DELETE查詢影響的行數,這些查詢是使用mysql_query執行的。
通常對於mysql_函數,返回碼0表示沒有行受影響;正數表示實際結果,通常是受影響的行數。
如前所述,當使用mysql_affected_rows時可能出現未期望的結果。讓我們先討論受INSERT語句影響的行數,它將按預期進行操作。將下列代碼添加到程式 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;
}

正如預期,插入的行數為1。
現在,我們更改代碼,所以 '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));
}

現在假設子表中有的資料,如下:

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

如果我們執行update1,希望報告的受影響行數為4,但是實際上程式報告2,因為它僅必須更改2行,雖然WHERE子句標識了4行。如果想讓mysql_affected_rows報告的結果為4這可能是熟悉其它資料庫的人所期望的),則需要記住將CLIENT_FOUND_ROWS標誌傳遞到mysql_real_connect,在 update2.c中的程式如下:

複製代碼 代碼如下:if (mysql_real_connect(&my_connection, "localhost",
"rick", "bar", "rick", 0, NULL, CLIENT_FOUND_ROWS)) {

如果我們在資料庫中複位元據,然後運行帶有這種修改的程式,則它報告的行數為4。
函數mysql_affected_rows還有最後一個奇怪之處,它發生在從資料庫中刪除資料時。如果使用WHERE子句,則mysql_affected_rows將按預期返回刪除行數。但是,如果沒有WHERE子句,則刪除所有行,報告受影響的行數卻為0。這是因為由於效率原因最佳化刪除整個表。這種行為不受CLIENT_FOUND_ROWS選項標誌的影響。

返回資料的語句

現在是時候討論SQL的最普遍用法了,從資料庫檢索資料的SELECT語句。

MySQL 還支援返回結果的SHOW、DESCRIBE和EXPLAIN SQL語句,但是這裡不考慮它們。按慣例,手冊中包含這些語句的說明。
您將會從PostgreSQL章記起,可以從PQexec中的SQL SELECT 語句檢索資料,這裡馬上擷取所有資料,或者使用遊標從資料庫中逐行檢索資料,以便搞定大資料。
由於完全相同的原因,MySQL的檢索方法幾乎完全相同,雖然它實際上不用遊標的形式描述逐行檢索。但是,它提供了縮小這兩種方法間差異的API,如果需要,它通常使兩種方法的互換更加容易。
通常,從MySQL資料庫中檢索資料有4個階段:

發出查詢
檢索資料
處理資料
執行所需的任何整理

象以前一樣,我們使用mysql_query發出查詢。資料檢索是使用mysql_store_result或mysql_use_result完成的,這取決於想如何檢索資料,隨後使用mysql_fetch_row調用序列來處理資料。最後,必須調用mysql_free_result以允許MySQL執行任何所需的整理。
全部立即資料檢索的函數
可以從SELECT語句(或其他返回資料的語句)中檢索完所有資料,在單一調用中,使用mysql_store_result: 複製代碼 代碼如下:MYSQL_RES *mysql_store_result(MYSQL *connection);

必須在mysql_query檢索資料後才能調用這個函數,以在結果集中儲存該資料。這個函數從伺服器中檢索所有資料並立即將它儲存在客戶機中。它返回一個指向以前我們從未遇到過的結構(結果集結構)的指標。如果語句失敗,則返回NULL。
使用等價的PostgreSQL時,應該知道返回NULL意味著已經發生了錯誤,並且這與未檢索到資料的情況不同。即使,傳回值不是NULL,也不意味著當前有資料要處理。
如果未返回NULL,則可以調用mysql_num_rows並且檢索實際返回的行數,它當然可能是0。 複製代碼 代碼如下:my_ulonglong mysql_num_rows(MYSQL_RES *result);

它從mysql_store_result取得返回的結果結構,並且在該結果集中返回行數,行數可能為0。如果mysql_store_result成功,則mysql_num_rows也總是成功的。
這種mysql_store_result和mysql_num_rows的組合是檢索資料的一種簡便並且直接的方法。一旦mysql_store_result成功返回,則所有查詢資料都已經儲存在客戶機上並且我們知道可以從結果結構中檢索它,而不用擔心會發生資料庫或網路錯誤,因為對於程式所有資料都是本地的。還可以立即發現返回的行數,它可以使編碼更簡便。如前所述,它將所有結果立即地發送回客戶機。對於大結果集,它可能耗費大量的伺服器、網路和客戶機資源。由於這些原因,使用更大的資料集時,最好僅檢索需要的資料。不久,我們將討論如何使用mysql_use_result函數來完成該操作。
一旦檢索了資料,則可以使用mysql_fetch_row來檢索它,並且使用mysql_data_seek、mysql_row_seek、mysql_row_tell操作結果集。在開始檢索資料階段之前,讓我們先討論一下這些函數。 複製代碼 代碼如下:MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

這個函數採用從儲存結果中擷取的結果結構,並且從中檢索單一行,在行結構中返回分配給您的資料。當沒有更多資料或者發生錯誤時,返回NULL。稍後,我們將回來處理這一行中的資料。 複製代碼 代碼如下:void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);

這個函數允許您進入結果集,設定將由下一個擷取操作返回的行。offset是行號,它必須在從0到結果集中的行數減 1 的範圍內。傳遞0將導致在下一次調用mysql_fetch_row時返回第一行。 複製代碼 代碼如下:MYSQL_ROW_OFFEST mysql_row_tell(MYSQL_RES *result);

這個函數返回一個位移值,它表示結果集中的當前位置。它不是行號,不能將它用於mysql_data_seek。但是,可將它用於: 複製代碼 代碼如下:MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset);

它移動結果集中的當前位置,並返回以前的位置。
有時,這一對函數對於在結果集中的已知點之間跳轉很有用。請注意,不要將row tell和row seek使用的位移值與data_seek使用的行號混淆。這些是不可交換的,結果將是您所希望看到的。 複製代碼 代碼如下:void mysql_free_result(MYSQL_RES *result);

完成結果集時, 必須總是調用這個函數,以允許MySQL庫整理分配給它的對象。
檢索資料
現在開始編寫從資料庫中檢索資料的第一個程式。我們將選擇所有年齡大於5的行的內容。不幸的是我們還不知道如何處理這個資料,所以我們能做的只有迴圈檢索它。這便是 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;
}

檢索結果集並迴圈通過已檢索的資料的重要部分都已反白。

一次檢索一行資料

要按需要逐行檢索資料,而不是立即擷取全部資料並將它儲存在客戶機中,可以將mysql_store_result調用替換成 mysql_use_result: 複製代碼 代碼如下:MYSQL_RES *mysql_use_result(MYSQL *connection);

這個函數還取得一個連線物件並返回結果結合指標,或者出錯時返回NULL。與mysql_store_result相似,它返回指向結果集對象的指標;關鍵的不同點在於返回時,實際上沒有將任何資料檢索到結果集,只是初始化結果集以準備好檢索資料。

參考資料

您可以參閱本文在developerWorks全球網站上的英文原文.

本文章取自Wrox Press Ltd出版的Professional Linux一書的第5章。

關於作者

Rick Stones是一位系統設計師,他在一家大型泛歐製藥分銷和分配公司的IT部門工作。從1985年開始,他一直在使用各種形式的 UNIX,並且發現帶有早期 .99 CD-ROM發行版的Linux。他用各種語言編寫UNIX、Linux和其它平台的軟體,同時還安裝並管理幾台Linux伺服器。在非常有限的業餘時間,他努力提高他的鋼琴演奏技巧。

從大學時代開始接觸C和UNIX V6時起,Neil Matthew對於UNIX和Linux已經超過20年的經驗。從那時起他就在IT業工作,主要從事通訊軟體的開發,一直保持對於深奧的程式設計語言和開發技術的熱情。現在,他作為系統設計師,對技術戰略和QA提出建議。他熱心於在公司企業內建立Linux商業案例。業餘時間,寫作或騎馬為樂,Neil努力勸說他的妻子和兩個孩子與他一起在鄉間散步。Neil參與編寫了Wrox Press發行的好幾本書,最著名的是共同著作了Beginning Linux Programming和Professional Linux Programming。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.