SQL 支持

如下表所示,EGL 生成的代码可以访问任何目标系统上的关系数据库。

目标系统 对访问关系数据库的支持
AIX®、iSeries™、Linux™、Windows® 2000/NT/XP 和 UNIX® System Services JDBC 提供了对 DB2® UDB、Oracle 或 Informix® 的访问

开发程序时,可以象使用大多数其它语言编写程序时那样编写 SQL 语句。为了方便您工作,EGL 提供了 SQL 语句模板来供您填写。

另一种方法是,在编写 EGL 语句时,可以将 SQL 记录用作 I/O 对象。以此方式使用记录意味着通过对提供给您的 SQL 语句进行定制或者通过依靠缺省 SQL 语句(从而不需要编写 SQL)来访问数据库。

在任何一种情况下,您都要了解 EGL 对 SQL 支持的下列方面:

EGL 语句和 SQL

下表列示了可以用来访问关系数据库的 EGL 关键字。此表还显示了与每个关键字相对应的 SQL 语句的概述。例如,在编写 EGL add 语句时,将生成 SQL INSERT 语句。

在许多商业应用程序中,使用 EGL open 语句和各种 get by position 语句。这些代码帮助您声明、打开和处理游标,后者是执行下列操作的运行时实体:
  • 返回结果集,这是满足搜索条件的行的列表
  • 指向结果集中的特定行

可以使用 EGL open 语句来调用存储过程。 该存储过程由 EGL 外部编写的逻辑组成的并存储在数据库管理系统中,它也返回结果集。(另外,可以使用 EGL execute 语句来调用存储过程。)

下列各节提供有关处理结果集的详细信息。

如果您打算显式地编写 SQL 语句,则使用 EGL execute 语句,并有可能使用 EGL prepare 语句。

关键字/用途 SQL 语句的概述 是否可以修改 SQL?
add

在数据库中添加一行;或者(如果使用 SQL 记录动态数组的话),根据连续数组元素的内容添加一组行。

INSERT row(如果指定动态数组,则重复地发生)。
close

释放未处理的行。

CLOSE cursor。
delete

从数据库中删除一行。

DELETE row。该行是通过下列两种方法的其中一种选择的:
  • 当您调用带有 forUpdate 选项的 get 语句时(当您希望选择带有同一键值的若干行中的第一行时,这是合适的)
  • 当您调用带有 forUpdate 选项的 open 语句并接着调用 get next 语句时(当您希望选择一组行并在循环中处理检索到的数据时,这是合适的)
forEach

标记在循环中运行的一组语句的开始。仅当指定的结果集可用时才会发生第一次迭代,并且该迭代会持续(在大多数情况下)至处理结果集的最后一行。

EGL 将 forEach 语句转换成在循环内部运行的 SQL FETCH 语句。
freeSQL

释放与动态预编译 SQL 语句相关联的所有资源,关闭与该 SQL 语句相关联的任何打开游标。

 
get(也称为 get by key value

从数据库中读取一行;或者(如果使用 SQL 记录动态数组的话),将连续的行读入数组的连续元素。

SELECT row,但仅当设置了 singleRow 选项时才如此。否则,下列规则适用:
  • EGL 将 get 语句转换为以下内容:
    • DECLARE cursor with SELECT 或(如果设置了 forUpdate 选项的话)DECLARE cursor with SELECT FOR UPDATE。
    • OPEN cursor。
    • FETCH row。
  • 如果未指定 forUpdate 选项,则 EGL 还关闭游标。
  • 动态数组不支持 singleRow 和 forUpdate 选项;在该情况下,EGL 运行时声明并打开游标,访存一系列行,然后关闭游标。
get absolute

读取结果集中由 open 语句选择的用数字指定的行。

EGL 将 get absolute 语句转换为 SQL FETCH 语句。
get current

读取结果集中由 open 语句选择的游标已经定位的行。

EGL 将 get current 语句转换为 SQL FETCH 语句。
get first

读取结果集中由 open 语句选择的第一行。

EGL 将 get first 语句转换为 SQL FETCH 语句。
get last

读取结果集中由 open 语句选择的最后一行。

EGL 将 get last 语句转换为 SQL FETCH 语句。
get next

读取结果集中由 open 语句选择的下一行。

EGL 将 get next 语句转换为 SQL FETCH 语句。
get previous

读取结果集中由 open 语句选择的上一行。

EGL 将 get previous 语句转换为 SQL FETCH 语句。
get relative

读取结果集中由 open 语句选择的用数字指定的行。该行是根据结果集中的游标位置指定的。

EGL 将 get relative 语句转换为 SQL FETCH 语句。
execute

允许运行 SQL 数据定义语句(例如,CREATE TABLE 类型)或数据处理语句(例如,INSERT 或 UPDATE 类型);或者运行不以 SELECT 子句开头的预编译 SQL 语句。

您编写的 SQL 语句可用于数据库管理系统。
execute 的主要用途是编写单一 SQL 语句,该 SQL 语句在生成时要定义完整的格式,如以下示例所示:
        try
  execute
  #sql{    // no space after "#sql"
    delete
    from EMPLOYEE
    where department =
      :myRecord.department  
  };
onException
  myErrorHandler(10);
  end

定义了完整格式的 SQL 语句可以在 WHERE 子句中包含主变量。

open

从关系数据库中选择一组行,以供 get next 语句以后检索。

EGL 将 open 语句转换为 CALL 语句(用于访问存储过程),或转换为下列语句:
  • DECLARE cursor with SELECT 或 DECLARE cursor with SELECT FOR UPDATE。
  • OPEN cursor。
prepare

指定一个 SQL PREPARE 语句,该语句包含(可选)只有在运行时才知道的详细信息;通过运行 EGL execute 语句或者(如果 SQL 语句以 SELECT 开头的话)通过运行 EGL open 或 get 语句来运行预编译 SQL 语句。

EGL 将 prepare 语句转换为 SQL PREPARE 语句,后者始终是在运行时构造的。在 EGL prepare 语句的以下示例中,每个参数标记(?)都是由后续 execute 语句中的 USING 子句解析的:
myString =
  "insert into myTable " +
  "(empnum, empname) " +
    "value ?, ?";

        try
  prepare myStatement
    from myString;
onException
  // exit the program
        myErrorHandler(12);
end

  
        try
  execute myStatement
  using :myRecord.empnum,
        :myRecord.empname;
onException
  myErrorHandler(15);
end

  
replace

将更改了的行放回数据库中。

UPDATE row。该行是通过下列两种方法的其中一种选择的:
  • 当您调用带有 forUpdate 选项的 get 语句时(当您希望选择带有同一键值的若干行中的第一行时,这是合适的);或者
  • 当您调用带有 forUpdate 选项的 open 语句并接着调用 get next 语句时(当您希望选择一组行并在循环中处理检索到的数据时,这是合适的)。
注: 在任何情况下都不能通过编写单个 EGL 语句来更新多个数据库表。

结果集处理

更新一系列行的常用方法如下所示:
  1. 通过运行带有 forUpdate 选项的 EGL open 语句来声明并打开游标;该选项导致将选择的行锁定,以便接着进行更新或删除
  2. 通过运行 EGL get next 语句来访存行
  3. 在一个循环中执行以下操作:
    1. 更改主变量中的数据(您已将数据检索到那些主变量中)
    2. 通过运行 EGL replace 语句来更新行
    3. 通过运行 EGL get next 语句来访存另一行
  4. 通过运行 EGL 函数 commit 来提交更改。

打开游标的语句和对该游标的行执行操作的语句是通过结果集标识一一相关的,该结果集标识在程序中的所有结果集标识、程序变量和程序参数中必须是唯一的。在打开游标的 open 语句中指定该标识,并在影响单个行的 get nextdeletereplace 语句中以及在关闭游标的 close 语句中引用同一标识。有关其它详细信息,请参阅 resultSetID

下列代码说明在您自己编写 SQL 时如何更新一系列行:
  VGVar.handleHardIOErrors  = 1;

          try
    open selectEmp forUpdate with
    #sql{  										// no space after "#sql"
      select empname
      from EMPLOYEE
      where empnum >= :myRecord.empnum
      for update of empname
    };
      
  onException
    myErrorHandler(8);  // exits program
  end

  
          try
    get next from selectEmp into :myRecord.empname;
  onException
    if (sysVar.sqlcode != 100)
      myErrorHandler(8);  // exit the program
    end

    end

  
  while (sysVar.sqlcode != 100)
    myRecord.empname = myRecord.empname + " " + "III";

            try
      execute
      #sql{
        update EMPLOYEE
        set empname = :empname
        where current of selectEmp
      };
    onException
      myErrorHandler(10); // exits program
    end

  
            try
      get next from selectEmp into :myRecord.empname;
    onException
      if (sysVar.sqlcode != 100)
        myErrorHandler(8);  // exits program
      end

      end

    end  // end while; cursor is closed automatically
       // when the last row in the result set is read

  sysLib.commit;

如果您希望避免上一个示例中的一些复杂性,请考虑使用 SQL 记录。通过使用 SQL 记录,可以使代码简化以及使用不随数据库管理系统的改变而变化的 I/O 错误值。下一个示例等同于上一个示例,但使用名为 emp 的 SQL 记录:

  VGVar.handleHardIOErrors  = 1;

          try
    open selectEmp forUpdate for emp;
  onException
    myErrorHandler(8);  // exits program
  end

  
          try
    get next emp;
  onException
    if (sysVar.sqlcode not noRecordFound)
      myErrorHandler(8);  // exit the program
    end

    end

  
  while (sysVar.sqlcode not noRecordFound)
    myRecord.empname = myRecord.empname + " " + "III";

            try
      replace emp;
    onException
      myErrorHandler(10); // exits program
    end

  
            try
      get next emp;
            on exception 
      if (sysVar.sqlcode not noRecordFound)
        myErrorHandler(8);  // exits program
      end

      end

    end  // end while; cursor is closed automatically
       // when the last row in the result set is read

  sysLib.commit;

下列各节描述 SQL 记录。

SQL 记录和它们的使用

SQL 记录是基于 SQL 记录部件的变量。此类型的记录允许您与关系数据库进行交互,就象是正在访问文件一样。例如,如果变量 EMP 基于引用数据库表 EMPLOYEE 的 SQL 记录部件,则可以在 EGL add 语句中使用 EMP:
  add EMP;
在此例中,EGL 将 EMP 中的数据插入到 EMPLOYEE 中。SQL 记录还包含状态信息,因此,在 EGL 语句运行后,可以测试 SQL 记录以根据数据库访问操作所得到的 I/O 错误值来有条件地执行任务:
  VGVar.handleHardIOErrors  = 1;

          try
    add EMP;
  onException
    if (EMP is unique)     // if a table row
                          // had the same key
              myErrorHandler(8);
    end

      end
SQL 记录(如 EMP)允许您与关系数据库进行交互,如下所示:
  • 声明 SQL 记录部件和相关的 SQL 记录
  • 定义一组 EGL 语句,其中每个 EGL 语句都将 SQL 记录用作 I/O 对象
  • 接受 EGL 语句的缺省行为,或进行适合于业务逻辑的 SQL 更改

声明 SQL 记录部件和相关记录

您声明 SQL 记录部件并将每个记录项与关系表或视图中的一列相关联。可以通过 EGL 编辑器的检索功能让 EGL 自动执行此关联,如下面的声明时的数据库访问中所述。

如果 SQL 记录部件不在固定记录部件中,您可以加入基本字段和其它变量。您可能特别希望加入下列几种变量:
  • 其它 SQL 记录。每一种 SQL 记录表示父表与子表之间的一对一关系。
  • SQL 记录数组。每一种 SQL 记录数组表示父表与子表之间的一对多关系。

只有基本类型的字段可以表示数据库列。

如果字段前有级别号,则 SQL 记录部件是固定记录部件。下列规则适用:
  • 每个 SQL 记录部件中的结构都必须是平面的(无层次结构)
  • 所有字段必须是基本字段,而不是类型为 BLOB、CLOB 或 STRING 的字段
  • 任何记录字段都不能是结构字段数组

在声明 SQL 记录部件之后,声明基于该部件的 SQL 记录。

定义与 SQL 相关的 EGL 语句

可以定义一组 EGL 语句,每个 EGL 语句都将 SQL 记录用作语句中的 I/O 对象。对于每个语句,EGL 提供了隐式 SQL 语句,该语句并未包含在源代码中,而是由 SQL 记录与 EGL 语句的组合所隐含的。例如,对于 EGL add 语句,隐式 SQL INSERT 语句将给定记录项的值放入相关联的表列。如果 SQL 记录包含未指定表列的记录项,则 EGL 根据一个假定来构造隐式 SQL 语句,即假定记录项名与列名完全相同。

使用隐式 SELECT 语句

当定义使用 SQL 记录并生成 SQL SELECT 语句或游标声明的 EGL 语句时,EGL 将提供隐式 SQL SELECT 语句。(如果有游标声明的话,该语句就嵌入在游标声明中。)例如,可以声明一个名为 EMP 并基于以下记录部件的变量:
  Record Employee type sqlRecord
    { tableNames = [["EMPLOYEE"]],
      keyItems = ["empnum"] }
    empnum decimal(6,0);
    empname char(40);
  end

  
然后,可以编写 get 语句:
  get EMP;
隐式 SQL SELECT 语句如下所示:
  SELECT empnum, empname
  FROM   EMPLOYEE
  WHERE  empnum = :empnum
EGL 还将一个 INTO 子句放到独立的 SELECT 语句中(如果未涉及游标声明的话),或放到与游标相关联的 FETCH 语句中。INTO 子句列示主变量,那些主变量从 SELECT 语句的第一个子句中列示的列接收值:
  INTO :empnum, :empname
隐式 SELECT 语句将每个列值读入相应的主变量、引用 SQL 记录中指定的表并具有一个搜索条件(WHERE 子句),该搜索条件取决于两个因素的组合
  • 对记录属性 defaultSelectCondition 指定的值;以及
  • 两组值之间的关系(例如,等同性):
    • 组成表键的列的名称
    • 组成记录键的主变量的值
如果将数据读入 SQL 记录动态数组(可以通过 get 语句做到这一点),就会发生一种特殊的情况:
  • 游标被打开,数据库中连续的行被读入到数组的连续元素中,结果集被释放,游标被关闭。
  • 如果未指定 SQL 语句,则搜索条件取决于记录属性 defaultSelectCondition,但也取决于下列各组值之间的关系(明确地说,是大于等于关系):
    • 列的名称,这些名称是在 EGL 语句中指定项时间接指定的
    • 那些项的值

    属性 defaultSelectCondition 中指定的任何主变量都必须位于作为动态数组基础的 SQL 记录之外。

有关隐式 SELECT 语句(这种语句随着关键字的变化而变化)的详细信息,请参阅 getopen

将 SQL 记录与游标配合使用

当使用 SQL 记录时,可以通过在若干个 EGL 语句中使用同一个 SQL 记录来使游标处理语句相关,正如可以使用结果集标识做到这一点一样。但是,由结果集标识指示的任何交叉语句关系都优先于由 SQL 记录指示的关系;在某些情况下,必须指定 resultSetID。

另外,对于特定的 SQL 记录,只能打开一个游标。如果在已对同一个 SQL 记录打开了一个游标的情况下 EGL 语句打开另一个游标,则生成的代码会自动关闭第一个游标。

定制 SQL 语句

给定将 SQL 记录用作 I/O 对象的 EGL 语句,可以按照下列两种方式的其中一种方式继续:
  • 可以接受隐式 SQL 语句。在这种情况下,对 SQL 记录部件所作的更改会影响在运行时使用的 SQL 语句。例如,如果以后指示要将另一条记录项用作 SQL 记录的键,则 EGL 会更改任何基于该 SQL 记录部件的游标声明中使用的隐式 SELECT 语句。
  • 或者,您可以选择使 SQL 语句成为显式的。在这种情况下,该 SQL 语句的详细信息是与 SQL 记录部件分开的,对 SQL 记录部件所作的任何后续更改都不影响在运行时使用的 SQL 语句。

    如果从源代码中除去显式 SQL 语句,则隐式 SQL 语句(如果有的话)在生成时再次可用。

使用记录中的记录的示例

要允许程序检索有关某个部门中的一系列职员的数据,可创建两个记录部件和一个函数,如下所示:
	DataItem DeptNo { column = deptNo } end

 Record Dept type SQLRecord
   deptNo DeptNo;
   managerID CHAR(6);
   employees Employee[];
 end

  
 Record Employee type SQLRecord
   employeeID CHAR(6);
   empDeptNo DeptNo;
 end

  
 Function getDeptEmployees(dept Dept)
   get dept.employees usingKeys dept.deptNo;
 end

  

测试与设置 NULL

在某些情况下,EGL 在内部保留一个空指示符,以便在代码中表示变量的子集。如果接受这一缺省行为,EGL 在内部仅为具有下列特征的每个变量保留一个空指示符:
  • 位于 SQL 记录中
  • 是使用设置为 yes 的属性 isNullable 声明的

不要象在某些语言中那样在 SQL 语句中对空指示符编写主变量。要测试可空主变量中的 NULL,请使用 EGL if 语句。也可以测试被截断值的检索,但仅当空指示符可用时才能这样做。

可以通过两种方法的其中一种来使 SQL 表列为 NULL:
  • 使用 EGL set 语句来使可空主变量为 NULL,然后将相关 SQL 记录写至数据库;或者
  • 使用适当的 SQL 语法,通过从头开始编写 SQL 语句或通过定制与 EGL addreplace 语句相关联的 SQL 语句

有关 NULL 处理的其它详细信息,请参阅 itemsNullableSQL 项属性

声明时的数据库访问

如果(在声明时)访问数据库,并且该数据库的特征和代码在运行时访问的数据库相似时,可以获得下列益处:
  • 如果所访问数据库表或视图等同于与 SQL 记录相关联的表或视图,则可以使用 EGL 部件编辑器的检索功能来创建或覆盖记录项。检索功能访问存储在数据库管理系统中的信息,以使所创建的项的数目和数据特征反映表列的数目和特征。在调用检索功能之后,可以重命名记录项、删除记录项以及对 SQL 记录进行其它更改。
  • 在声明时访问具有相应结构的数据库可帮助确保 SQL 语句在运行时对于等效数据库是有效的。

检索功能将创建一些记录项,每个这样的记录项都与相关表列同名(或几乎同名)。

不能检索使用 DB2 条件 WITH CHECK OPTIONS 定义的视图。

有关使用检索功能的更多详细信息,请参阅检索 SQL 表数据。有关命名的详细信息,请参阅设置 SQL 检索首选项

要在声明时访问数据库,可在首选项页面中指定连接信息,如设置 SQL 数据库连接首选项中所述。

使用条款 | 反馈
(C) Copyright IBM Corporation 2000, 2005. All Rights Reserved.