当前位置: 首页 > Linux学院 > 程序设计 > 软件工程 > 使用XL C/C++编译器中提供的数据访问SQL工具

使用XL C/C++编译器中提供的数据访问SQL工具

2014-07-26 10:05 来源:IBM 作者:Igor Todorovski 人气指数: 我要评论

IBM 用于 z/OS 的 XL C/C++ 编译器支持在 C/C++ 程序中使用嵌入式 SQL 语句。本文假设您使用了 XL C/C++ DB2 协处理器。文中会描述与 z/OS 上的嵌入式 SQL XL C/C++ 程序中的 SQL 数据交互的各种方法。

使用主变量从 SQL 获取数据

从 SQL 表获取数据的最基本方法是使用主变量(host variables)。主变量允许 C/C++ 程序与 DB2 进行通信。

示例:主变量

备注:本文中的所有示例都会引用清单 1 中的学生表。

清单 1. 学生表

EXEC SQL CREATE TABLE Students                                              
(
   STUDENTNO INT NOT NULL,
   FIRSTNAME VARCHAR(12) NOT NULL,
   LASTNAME  VARCHAR(15) NOT NULL,
   DEPARTMENT CHAR(3) NOT NULL,
   PHONENUMBER CHAR(7),
   AGE  SMALLINT,
   GPA  FLOAT(5)
);

要从一个 SQL 表获取数据,更新、删除其中的数据或向其中插入数据,首先必须在应用程序中声明一个主变量。主变量是一个 C/C++ 变量,通常具有 C/C++ 类型,比如 int、float、char 等。

XL C/C++ DB2 协处理器将主变量数据存储在一个数据库请求模块 (DBRM) 数据集中,或者分层文件系统 (Hierarchical File System, HFS) 文件中。

声明主变量

主变量是在一个声明节(declare section block)中定义的。声明一个主变量会向协处理器表明可以从 SQL 语句获取数据和向 SQL 提供数据。未在声明节中声明的变量不会被 SQL 语句接受。

EXEC SQL BEGIN DECLARE SECTION;
    int student_number;
EXEC SQL END DECLARE SECTION;

BEGIN 和 END 声明节命令可放在任何有效的 C/C++ 声明的两端,表明该变量是一个主变量。

清单 2 在表 Students 中查询学生编号 “John Doe”。结果被存储在主变量 student_number 中。

清单 2. 对一个主变量的 SQL 查询

EXEC SQL SELECT STUDENTNO
       INTO :student_number
       FROM Students
       WHERE FIRSTNAME = 'John'
       AND LASTNAME = 'Doe';

备注:主变量以 “:” 字符为前缀。这是主变量惟一可从 SQL 语句内访问的方式。没有这个前缀,变量名称会被视为一个字符串。此外,INTO子句用于将 SELECT 语句的结果存储在一个主变量中。

主变量细节

主变量可以是一个标准的类型修饰符、一个数组或一个结构。用于其他变量的相同范围规则也同样适用于主变量。可以像任何标准 XL C/C++ 变量一样使用主变量,此外,还可以将它用在 SQL 语句中。

其他可接受的主变量类型包括数字、字符、图形、二进制、LOB(大对象)、XML 和 ROWID 主变量。您也可以指定一个结果集、表、LOB 定位符和 LOB 或 XML 文件基准变量。这些主变量更先进,已超出本文的介绍范围。

备注:不是所有 XL C/C++ 数据类型都拥有等效的 SQL 类型。例如,typedefs、long long 和寄存器变量无法被声明为主变量。有关其他支持的类型的详细信息,请参阅 应用编程和 SQL 指南。

真实的 SQL 数据访问示例

案例 1. 将一组学生插入一个表中

回想一下清单 1 中的 Students 表。为了填充该表,您必须向该表插入一组学生记录。该表包含以下模式:

STUDENTNO → INT  
FIRSTNAME → VARCHAR(12)
LASTNAME  → VARCHAR(15)
DEPTARTMENT → CHAR(3)
PHONENUMBER → CHAR(7)
AGE → SMALLINT
GPA →  FLOAT(5)

假设一种学校模式会提示输入学生的信息。该程序的声明节定义如下:

EXEC SQL BEGIN DECLARE SECTION;
    int student_number;
    char firstname[13];
    char lastname[16];
    char department[4];
    char phonenumber[8];
    short age;
    float gpa;
EXEC SQL END DECLARE SECTION;

字符字段需要特别注意。SQL 语句仅接受以下字符表示:

  • 单字符格式
  • 空字符终止的字符 (null-terminated character) 格式
  • VARCHAR 结构化格式
  • CLOB(字符大对象)

例如 strcpy(firstname, "John"); 是空字符终止的字符格式的一个例子。

清单 3. 插入学生

EXEC SQL INSERT INTO Students
VALUES (:student_number, :firstname, :lastname,
        :department, :phonenumber, :age, :gpa);

每个主变量对应于该表中的一个字段,会使用数据填充该字段。

案例 2. 选择将一条学生记录插入主结构中

一个典型的用例是选择一个完整记录。无需为每个字段声明一个主变量,应用程序可使用一个主结构。主结构在原理上类似于 C 结构体,但它封装了一个主变量集合。

对于 Students 表,该结构定义如下所示:

EXEC SQL BEGIN DECLARE SECTION;
struct Student {
    int student_number;
    char firstname[13];
    char lastname[16];
    char department[4];
    char phonenumber[8];
    short age;
    float gpa;
} student_record;
EXEC SQL END DECLARE SECTION;

现在,您可以使用以下代码,在 SELECT 语句中引用 student_record 主结构:

EXEC SQL
  SELECT STUDENTNO, FIRSTNAME, LASTNAME, DEPARTMENT,
         PHONENUMBER, AGE, GPA
    INTO :student_record
    FROM Students
    WHERE STUDENTNO = 001;

student_record 主结构的每个元素将填入与学生编号 001 关联的行的字段值。

案例 3. 获取前 100 名学生 GPA 的列表

现在数据库中已填入了一组学生,您可继续获取一个学生 GPA 列表。

您可以使用以下声明语句将主变量声明为数组:

EXEC SQL BEGIN DECLARE SECTION;
    float gpa_list[100];
EXEC SQL END DECLARE SECTION;

使用游标获取学生 GPA 列表

要在单个查询中获取多行,应用程序必须使用游标。

游标 指向一个 SELECT 语句所确定的一个行子集。然后,应用程序可从这个子集抓取 任意数量的行。例如,假设一个查询选择 1000 个 GPA。这 1000 个 GPA 存储在一个中间结果表中。您可以从这个中间表中一次将任意数量的行抓取 到一个数组中。

清单 4. 使用游标抓取前 100 个 GPA

EXEC SQL DECLARE STUDENTS_C1 CURSOR WITH ROWSET POSITIONING
  FOR SELECT gpa FROM STUDENTS WHERE 1=1 ORDER BY GPA DESC;
EXEC SQL OPEN STUDENTS_C1;
EXEC SQL FETCH NEXT ROWSET FROM STUDENTS_C1 FOR 100
  ROWS INTO :gpa_list;
EXEC SQL CLOSE STUDENTS_C1;

第一步声明了一个名为 STUDENTS_C1 的游标并将它与查询相关联:

 SELECT gpa FROM Students WHERE 1=1 ORDER BY GPA DESC;

此查询的结果存储在一个结果表中。声明游标之后,打开该游标。这会告诉 DB2,它已准备好处理来自 select 语句的第一行结果。随后,使用fetch 语句从结果表获取数据。这样,您可以控制获取的行数并定义数据存储在何处。最后,游标会关闭。

随后,您可以调用一次 fetch 语句从结果表中获取下 100 个 GPA。

游标的结果将 GPA 数据存储在一个主变量数组中,以方便获取。

for (int i = 0; i < 100; i++)
{
     printf("GPA: %f ", gpa_list[i]);
}

使用指示器变量识别空记录

尽管查询可能要求获取前 100 个 GPA,但表本身可能包含不到 100 个 GPA。如果 Students 表包含 10 条记录,那么该询问将在第 10 次迭代后 打印意外的值。

为了解决这个问题,DB2 提供了指示器变量。指示器变量包含一个小的整数值,表示关联的主变量的某些信息。

指示器变量可包含以下值:

  • 0 或一个正整数
    选择的值非空。
  • -1 
    选择的值为空值。
  • -2 
    由于字符串转换警告,发生数字字符串转换错误或得到空的结果
  • -3
    没有返回值
  • 正整数
    选择的值被截断,但不是空的。

举例而言,如果指示器变量是一个数组,而且获取了 10 个元素,并将它们存储在一个包含 100 个元素的数组中,那么指示器变量的前 10 个元素会被设置为 0。

要使用指示器变量,首先需要将它与 gpa_list 数组一起声明。指示器变量必须声明为 short。

清单 5. 初始化指示器变量

EXEC SQL BEGIN DECLARE SECTION;
    float gpa_list[100];
    short gpa_indicator[100];
EXEC SQL END DECLARE SECTION;
for (int i = 0; i<100; i++) {  gpa_indicator[i] = -1; }

gpa_indicator 中的每个元素最初被设置为 -1,这表示主变量数组最初完全是 “空的”。您可以修改

fetch 语句来包含指示器变量:

EXEC SQL FETCH NEXT ROWSET FROM STUDENTS_C1
  FOR 100 ROWS INTO :gpa_list :gpa_indicator;

请注意,在 fetch 语句中,指示器变量 gpa_indicator 在主变量 gpa_list 之后。指示器变量仅可用在主变量之后。

现在,可以修改该循环来使用指示器,并且仅打印成功获取的行(省略空变量),如下所示:

for (int i = 0; i < 100; i++)
{
    if (gpa_indicator[i] >= 0)
       printf("GPA: %f ", gpa_list[i]);
 }

将主变量作为参数传递

主变量可作为参数传递给用户函数,但在局部函数范围中,主变量被视为非主变量。此外,不能将函数参数放在 DECLARE SECTION 块中。

要解决这个问题,可声明一个局部主变量,为它分配该参数的值(适合简单类型)。

在这些情况下,局部主变量必须使用主变量参数进行初始化。

清单 6. 传递主变量参数

int selectGPA(int student_number)
{
EXEC SQL BEGIN DECLARE SECTION;
    // Initialize with a new local variable
    int student_number1 = student_number;  
    float gpa;
EXEC SQL END DECLARE SECTION;

EXEC SQL SELECT GPA
       INTO :gpa
       FROM STUDENTS
       WHERE :student_number1 = 12121;
}

int main()
{
EXEC SQL BEGIN DECLARE SECTION;
    int student_number;
EXEC SQL END DECLARE SECTION;

EXEC SQL SELECT STUDENTNO
       INTO :student_number
       FROM STUDENTS
       WHERE FIRSTNAME = "Bill"
       AND LASTNAME = "Doe";
selectGPA(student_number);
}

一种替代方法是以全局方式声明主变量。

为您推荐: SQL工具 编译器 XL C/C++
大家感兴趣的内容
小伙伴最爱的新闻
小伙伴还关注了以下信息
小伙伴关注的焦点

小伙伴都在关注的热门词

新服 缤纷活动 航海世纪 芈月传 暗黑道具 萌乐网 苹果发布会 最新谍照 三国令 剑雨江湖 怎样修炼战骑 页游 怎样修炼伙伴 木甲世界 仙侠道2 推黑科技 页游模式 武圣试炼场 街机玩法 蓝月传奇 个人BOSS玩法 哥们网 九阴绝学 仗剑出鞘 全新模式 范伟打天下 全新元神玩法 七大神兵简介 新手攻略 跑腿任务 门派五行 城战礼包 页游界 泥石流 傅园慧 经典网页游戏 耐玩 盘点 玉石攻略 提升角色 大黑 实装属性 神兵攻略 问鼎莽荒 莽荒纪 手持神兵 土豪梦 万世 开学清单 财富赚不停 天书世界 大黑游戏 资源战场 ppwan 天问 激战 全国大战 雄霸一方 新增宠物技能 绝对小能手 花千骨 三尾章鱼 风色轨迹 双枪手 弑之神 缤纷好礼 惊喜六重连 帮会 中秋福利 自制月饼 九阴真经 玩家 五周年纪念 纪念银币 名动三界 新服资料片 画江山 勇战妖魔 邪恶势力 上古降魔 老司机玩法 坐骑揭秘 黑科技 竞技场攻略 铁血皇城 披风玩法 书剑恩仇录 装备强化攻略 野外BOSS玩法 全网曝光 赤壁传说 半回合制国 ACT 奇珍商城 热血战歌 传奇宝藏抽奖 打开方式 门徒 门徒获取玩法 三大萌宠简介