To return expected results, you can:

  • Reduce the number of search terms. Each term you use focuses the search further.
  • Check your spelling. A single misspelled or incorrectly typed term can change your result.
  • Try substituting synonyms for your original terms. For example, instead of searching for "java classes", try "java training"
  • Did you search for an IBM acquired or sold product ? If so, follow the appropriate link below to find the content you need.
  • 更佳的结果 ——在嵌入式程序中返回丰富的存储过程结果集(一)

    Tony Poirier

    原文链接 : http://www.ibmsystemsmag.com/ibmi/developer/general/Better-Results/?page=1

    存储过程可以用于封装代码,允许逻辑保持一贯性,并且可以被多个应用程序共享。在分布式环境中,存储过程特别有助于减轻网络流量。它还可以把逻辑处理集中到一段代码中,并被多个程序使用。

    存储过程可以通过出参把数据返回给调用者,但这并不是存储过程返回信息的唯一方式。存储过程可以返回结果集(通过 select 语句得到的结果)给调用者,可以和调用者共享数据。由于调用者可以通过存储过程访问结果集,这就增加了一个存储过程可以提供的信息量。复杂逻辑和复杂查询可以被封装在一个单独的存储过程中,任何应用程序都可以调用这个存储过程,并且处理返回的结果集。一个存储过程甚至可以返回多个结果集给调用者。关于存储过程结果集的逻辑流程,请参见下图 1

    图像

    一个存储过程既可以是 SQL 存储过程,也可以是外部存储过程(一段用宿主语言编写的代码,并且通过 CREATE PROCEDURE 语句定义成为存储过程),还可以是任意程序。在 IBM i 操作系统上的 DB2 中,只要是可以通过 SQL 语言中的 CALL 语句调用的代码段或程序都可以被认为是存储过程。并且只要程序使用了 OPEN SET RESULT SETS 语句,都可以返回结果集给调用者。

    从某种程度上说,使用一个存储过程返回结果集给调用它的应用程序,和使用 CL 命令 OPNQYF 返回结果集给应用程序是类似的。但是存储过程的能力要远远强于 OPQRYF ,并且功能也更丰富。

    在已有的在几个版本中,可以使用 System i Access Family 客户端程序(如 ODBC ), SQL 调用级接口( Call Level Interface ), JDBC ,或是远程系统访问时用到的 DRDA 协议,对结果集进行访问;而 RPG COBOL 以及 C 程序就没有那么幸运了,它们还不可以访问结果集。然而在 IBM i 7.1 版本中,这一点发生了变化。 7.1 版本增加了对嵌入式 C C++ ILE COBOL OPM COBOL ,以及 ILE RPG 程序访问结果集的支持。新的 SQL 语句 ASSOCIATE LOCATOR ALLOCATE CURSOR DESCRIBE PROCEDURE ,以及 DESCRIBE CURSOR 就是嵌入式程序用于定位结果集并使用其数据的工具。这篇文章介绍了如何使用这些新的 SQL 语句,来获取嵌入式程序中存储过程返回的结果集的方法。

    一个存储过程可以返回两种不同类型的结果集:游标结果集和数组结果集。这篇文章主要举了游标结果集的例子。值得注意的是,存储过程的调用者并不需要知道返回的是游标结果集还是数组结果集。如果想了解关于数组结果集的信息,请参见《 DB2 for i SQL Reference 》手册。

    本文将按大家在后面使用这些 SQL 语句的一般顺序,逐一进行介绍。说起获得更优结果这个话题,大家可以从回答如下问题开始:结果集数据的数据类型是众所周知的,还是说结果集的使用者需要获取并了解结果集数据的大小和数据结构?这些问题的答案将会引领我们决定使用上述那些新 SQL 语句中的哪一条。

    结果集定位器( Result Set Locators

    结果集定位器是一个调用程序中的宿主变量( host variable ),它在存储过程的特定结果集和调用方程序的游标之间建立了一个链接。如:

    C 声明一个结果集定位器: my_locator

    Static SQL TYPE IS RESULT_SET_LOCATOR my_locator;

    COBOL 声明一个结果集定位器: MY-LOCATOR

    01 MY-LOCATOR SQL TYPE IS RESULT_SET_LOCATOR.

    RPG 声明一个结果集定位器: MYLOCATOR

    D MYLOCATOR S SQLTYPE(RESULT_SET_LOCATOR)

    通过 ASSOCIATE LOCATOR 语句,或是通过一个跟在 DESCRIBE PROCEDURE 语句后面的 GET DESCRIPTOR 语句,结果集定位器就会被分配到一个结果集的特定实例中。

    ASSOCIATE LOCATOR 语句

    ASSOCIATE LOCATOR 语句用来获取存储过程返回的每个结果集的结果集值。下面是一个关于返回 3 个结果集的存储过程 inventory_proc 的例子。

    ASSOCIATE LOCATORS (:inventory_locator1, :inventory_locator2, :inventory_locator3)

    WITH PROCEDURE inventory_proc;

    这三个定位器中每一个,在后面都可能被用于单独的 ALLOCATE CURSOR 语句中。

    当使用 ASSOCIATE LOCATOR 语句时,请注意以下几点:

    1. ASSOCIATE LOCATOR 语句必须在 CALL 语句调用存储过程的同一个调用中完成;

    2. 如果存储过程返回多个结果集,所有的结果集定位器都要在同一个 ASSOCIATE LOCATOR 语句中设定,不能用多个 ASSOCIATE LOCATOR 进行设定;

    3. 如果有多个 CALL 语句调用存储过程, ASSOCIATE LOCATOR 语句返回最后一个 CALL 语句的结果集定位器;

    4. 当使用 DRDA 连到另一个系统时,在 ASSOCIATE LOCATOR 语句中,最好在存储过程名称前加上其所在模式( schema )的名称进行限定;否则 i 系统上的 DB2 数据库需要搜索远端系统的系统表来确定哪个才是要用的有效的存储过程;

    5. 如果在 ASSOCIATE LOCATOR 语句中,设定的结果集定位器变量的个数少于存储过程返回的结果集个数,将会返回一个错误码为 SQL0494 的告警;

    6. 如果在 ASSOCIATE LOCATOR 语句中,设定的结果集个数多于存储过程返回结果集的个数,将会返回一个错误码为 SQL0387 的告警;

    7. 不论上述两种告警( SQL0494/SQL0387 )哪个发生,分配给定位器的结果集顺序和返回结果集的顺序是一致的。

    ALLOCATE CURSOR 语句

    ALLOCATE CURSOR 语句用来定义一个 SQL 游标,并且将其和一个结果集定位器变量关联。这种游标的使用方式和在程序中声明并打开的一般游标的使用方式完全相同。下面是一个使用 ALLOCATE CURSOR 语句的例子。

    ALLOCATE INVENTORY_CURSOR CURSOR FOR RESULT SET :inventory_locateor1;

    当使用 ALOCATE CURSOR 语句时,请注意这几点:

    1. 结果集定位器变量必须是一个由 ASSOCIATE LOCATORS DESCRIBE PROCEDURE 语句返回的、有效的,定位器变量值;

    2. 分配游标时,结果集定位器变量的值会被使用到。但如果定位器变量的值随后再发生变化,不会影响已分配的游标;

    3. 源程序中,与不同游标关联的结果集定位器变量的值应各异;

    4. 关闭一个已分配的游标( allocated cursor ),也会关闭在存储过程中定义的相关的结果集的游标。

    DESCRIBE PROCEDURE 语句

    DESCRIBE PROCEDURE 语句用来获取有关存储过程返回的结果集的信息。这些信息,如结果集个数,会被放到一个描述符( descriptor )或 SQLDA 中。如果应用程序已知道存储过程返回的结果集都是什么,就不需要使用 DESCRIBE PROCEDURE 语句了。

    下面是一些使用 DESCRIBE PROCEDURE 语句来获取存储过程 SALES_PROC 结果集信息的例子。第一个例子使用了描述符;第二个例子使用了 SQLDA

    1. DESCRIPTOR 的例子及可用值:

    DESCRIBE PROCEDURE SALES_PROC USING SQL DESCRIPTOR ‘SALES_DESCRIPTOR’;

    DB2_RESULT_SETS_COUNT 表明结果集的总数。 0 表示没有结果集被返回。

    每个结果集都有一个描述符区域项:

    DB2_RESULT_SET_LOCATOR 包含了和结果集关联的结果集定位器的值;

    DB2_RESULT_SET_ROWS 包含了结果集中估算的行数。 -1 表示在结果集中没有可用的行数估算值;

    DB2_CURSOR_NAME 包含了存储过程用于返回结果集的游标名称。

    2. SQLDA 的例子及可用值:

    DESCRIBE PROCEDURE SALES_PROC USING :sales_sqlda;

    SQLD 表示结果集的总数。 0 表示没有结果集被返回。

    对于每一个 SQLVAR

    SQLDATA 字段包含了和结果集关联的结果集定位器的值;

    SQLD_RESULT_SET_ROWS 字段(利用了 SQLIND 字段)包含了结果集中估算的行数。 -1 表示在结果集中没有可用的行数估算值;

    SQLNAME 字段包含了存储过程用于返回结果集的游标名称。

    在使用 DESCRIBE PROCEDURE 语句时,这几点请注意:

    1. DESCRIBE PROCEDURE 必须在 CALL 语句调用存储过程的同一个调用中完成;

    2. DESCRIBE PROCEDURE 语句不会返回程序所期望的参数信息;

    3. 当使用 DRDA 连到另一个系统时,在 DESCRIBE PROCEDURE 语句中,最好在存储过程名称前加上其所在模式( schema )的名称对其进行限定;否则 i 系统上的 DB2 数据库需要搜索远端系统的系统表来确定哪个才是要用的有效的存储过程。

    下面的“示例代码 1 ”中给出了使用 DESCRIBE PROCEDURE 语句的示例代码段。

    EXEC SQL CALL LARGE_ORDERS(:order_threshold);

    if (SQLCODE==466){

    EXEC SQL ALLOCATE DESCRIPTOR 'large_order_descriptor';

    EXEC SQL DESCRIBE PROCEDURE LARGE_ORDERS

    USING SQL DESCRIPTOR 'large_order_descriptor';

    EXEC SQL GET DESCRIPTOR 'large_order_descriptor'

    :result_sets_count = DB2_RESULT_SETS_COUNT;

    for (i = 1; i <= result_sets_count; i++) {

    EXEC SQL GET DESCRIPTOR 'large_order_descriptor'

    VALUE :i :curs_name = DB2_CURSOR_NAME,

    :large_order_locator = DB2_RESULT_SET_LOCATOR,

    :num_rows = DB2_RESULT_SET_ROWS;

    }

    }

    示例代码 1

    DESCRIBE CURSOR 语句

    DESCRIBE CURSOR 语句用来获取为结果集而打开或分配的游标的信息。这些信息,如列信息,会被放到一个描述符( descriptor )或 SQLDA 中。

    下面是一些使用 DESCRIBE CURSOR 语句来获取游标 INVENTORY_CURSOR 信息的例子。第一个例子使用了描述符;第二个例子使用了 SQLDA

    1. DESCRIPTOR 的例子:

    DESCRIBE CURSOR INVENTORY_CURSOR USING SQL DESCRIPTOR ‘INVENTORY_DESCRIPTOR’;

    执行 DESCRIBE CURSOR 语句后的描述符区域的内容,和执行 DESCRIBE 一条 SELECT 语句后的描述如区域的内容是一样的,但增加了以下的内容,这些内容可以通过 GET DESCRIPTION 语句获得:

    DB2_CURSOR_HOLDABILITY 表示游标是否将会被一个 commit 操作关闭;

    DB2_CURSOR_RETURNABILITY 表示游标指向的结果集是否可被返回;

    DB2_CURSOR_SCROLLABILITY 表示游标是否是可回滚的;

    DB2_CURSOR_SENSITIVITY 表示游标的灵敏级别;

    DB2_CURSOR_UPDATEABLITY 表示游标是否能被用于 UPDATE WHERE CURRENT 语句中;

    DB2_RESULT_SET_ROWS 包含了结果集中估算的行数。 -1 表示在结果集中没有可用的行数估算值。注意,这个变量在 item 级别有效,每一个 item 包含了相同的 DB2_RESULT_SET_ROWS 值。

    2. SQLDA 的例子:

    DESCRIBE CURSOR INVENTORY_CURSOR USING :inventory_sqlda;

    执行 DESCRIBE CURSOR 语句后 SQLDA 的内容,和执行 DESCRIBE 一条 SELECT 语句后的 SQLDA 的内容是一样的,但增加了以下的内容:

    SQLD_RESULT_SET_ROWS 字段(利用了 SQLIND 字段)包含了结果集中估算的行数。 -1 表示在结果集中没有可用的行数估算值。注意每一个 SQLVAR entry 都有相同的 SQLD_RESULT_SET_ROWS 值。

    使用 DESCRIBE CURSOR 语句时,同样需要注意以下这几点:

    1. DESCRIBE CURSOR 必须在游标被打开或分配的同一个调用中完成,这个游标不能已被关闭;

    2. DESCRIBE CURSOR 可以在一个游标被声明并打开时完成,或在一个游标被分配给一个结果集时完成。

    3. 如果应用程序已经知道了游标的格式,则不需要使用 DESCRIBE CURSOR 来获取游标信息了。