服务器 频道

在 MySQL 数据库中使用 C 执行 SQL 语句

  返回数据的语句
  现在是时候讨论 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_fetch_rowmysql_fetch_row
  
  MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
  
  
  这个函数采用从存储结果中获取的结果结构,并且从中检索单一行,在行结构中返回分配给您的数据。当没有更多数据或者发生错误时,返回 NULL。稍后,我们将回来处理这一行中的数据。
  
  mysql_data_seek
  
  void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);
  
  
  这个函数允许您进入结果集,设置将由下一个获取操作返回的行。offset 是行号,它必须在从 0 到结果集中的行数减 1 的范围内。传递 0 将导致在下一次调用 mysql_fetch_row 时返回第一行。
  
  my_sql_row_tell, mysql_row_seek
  
  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 使用的行号混淆。这些是不可交换的,结果将是您所希望看到的。
  
  mysql_free_result
  在迫不及待地使用这些新函数之前,我们需要知道的最后一个函数是 mysql_free_result。
  
  void mysql_free_result(MYSQL_RES *result);
  
  
  完成结果集时,必须总是调用这个函数,以允许 MySQL 库整理分配给它的对象。
  
  检索数据
  现在开始编写从数据库中检索数据的第一个程序。我们将选择所有年龄大于 5 的行的内容。不幸的是我们还不知道如何处理这个数据,所以我们能做的只有循环检索它。这便是 select1.c:
  
  #include <stdlib.h>
  #include <stdio.h>
  
  #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 相似,它返回指向结果集对象的指针;关键的不同点在于返回时,实际上没有将任何数据检索到结果集,只是初始化结果集以准备好检索数据。
  
  参考资料
  
  本文章取自 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。
  
0
相关文章