返回首页

gbase数据、南大通用产品文档:GBase8s访问集合

更新日期:2024年09月11日

GBase 8s 支持以下种类的集合:
SET 数据类型,存储唯一值并且没有顺序位置的元素的集合。
MULTISET 数据类型,存储可以是重复值并且没有顺序位置的元素的集合。
LIST 数据类型,存储可以是重复值并具有有序位置的元素的集合。
SQL 和 GBase 8s ESQL/C 使您能够使用 SQL 集合派生表子句访问集合的元素,
就像它们是表中的行。在 GBase 8s ESQL/C 中,集合派生表采用集合变量的形式。集合
变量是您检索集合的主机变量。
将集合检索到集合变量后,
可以对其进行带有限制的选择、
更新和删除操作。
重要:
当 SQL 语句引用集合变量时,
GBase 8s ESQL/C 而不是数据库服务器处理此
语句。
SQL 允许您通过将集合派生表实现为虚拟表来对集合执行只读(SELECT)操作。
访问集合派生表
当集合的 SELECT 语句不引用 GBase 8s ESQL/C 集合变量时,
数据库服务器执行此
查询。
例如,考虑以下模式:
create row type person(name char(255), id int);
create table parents(name char(255), id int,
children list(person not null));
可以使用以下 SELECT 语句从表 parent 选择孩子的名称和 ID:
select name, id from table(select children from parents

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 211 -

where parents.id = 1001) c_table(name, id);
要执行此查询,数据库服务器创建一个虚拟表(c_table),它来自 parents 表中
parents.id 等于 1001的行的 children 列表。
集合派生表的优势
将集合查询为虚拟表而不是通过集合变量进行查询的优点在于虚拟表提供
了更高效的访问。
相比之下,如果您要使用集合变量,可能需要分配多个变量和多个游标。例如,考虑
以下模式:
EXEC SQL create row type parent_type(name char(255), id int,
children list(person not null));
EXEC SQL create grade12_parents(class_id int,
parents set(parent_type not null));
可以如下 SELECT 语句所示的那样将集合派生表查询为虚拟表:
EXEC SQL select name into :host_var1
from table((select children from table((select parents
from grade12_parents where class_id = 1))
p_table where p_table.id = 1001)) c_table
where c_table.name like ’Mer%’;
要使用集合变量执行相同的查询,您需要执行以下语句:
EXEC SQL client collection hv1;
EXEC SQL client collection hv2;
EXEC SQL int parent_id;

EXEC SQL char host_var1[256];


EXEC SQL allocate collection hv1;
EXEC SQL allocate collection hv2;

EXEC SQL select parents into :hv1 from grade12_parents
where class_id = 1;
EXEC SQL declare cur1 cursor for select id, children
from table(:hv1);
EXEC SQL open cur1;
for(;;)
{
EXEC SQL fetch cur1 into :parent_id, :hv2;
if(parent_id = 1001)
break;
}
EXEC SQL declare cur2 cursor for select name from
table(:hv2));
EXEC SQL open cur2;
for(;;)

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 212 -

{
EXEC SQL fetch cur2 into :host_var1;
/* user needs to implement ’like’ function */
if(like_function(host_var1, "Mer%"))
break;
}
集合派生表的限制
以下限制适用于查询作为虚拟表的集合派生表:
它不能是 INSERT 、DELETE 或 UPDATE 语句的目标。
它不能是可以更新的任何游标或视图的基础表。
它不支持序数。例如,它不支持以下语句:
select name, order_in_list from table(select children
from parents where parents.id = 1001)
with ordinality(order_in_list);
如果集合派生表的底层集合表达式求值为空值,则会出现错误。
它不能引用在同一 FROM 子句中引用的表的列。例如:它不支持以下语句,因为集
合派生表I table(parents.children) 引用了 FROM 子句中的引用的表 parents:
select count(distinct c_id) from parents,
table(parents.children) c_table(c_name, c_id)
where parents.id = 1001
数据库服务器必须能够静态地确定底层集合表达式的类型。例如:数据库服务器不支
持:TABLE(?)。
数据库服务器不支持对主机变量的引用,而不将其转换为已知的集合类型。例如:不
必指定 TABLE(:hostvar),您必须转换主机变量:
TABLE(CAST(:hostvar AS type))
TABLE(CAST(? AS type))
如果底层集合是列表,它将不会保留列表中的行的顺序。
声明集合变量
要访问具有集合类型(LIST 、MULTISET 或 SET)的列的元素作为其数据类型,请
执行以下步骤:
删除 collection 主机变量,已归类和未归类的都删除。
给 collection 主机变量分配内存。
对 collection 主机变量执行任何 select 、insert 、update 或 delete 操作。
将 collection 主机变量的内容保存到集合列中。
集合数据类型的语法
使用集合数据类型来声明集合数据类型(SET 、MULTISET 或 LIST)列的主机变
量。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 213 -

如以下语法所示,必须使用 collection 关键字作为 collection 主机变量的数据类型。


元素
意义
限制
SQL 语法
element
type
collection 变量中的元素
的数据类型
可以是除 SERIAL 、
SERIAL8 、BIGSERIAL 、
TEXT 或 BYTE 之外的任何
数据类型。
GBase 8s SQL
指南:
语法 中的数据
类型段
variable
name
声明为 collection 变量
的 GBase 8s ESQL/C 变量的
名称

名称必须符合
变量名称的语言规
范规则。
集合变量可以是任何 SQL 集合类型:LIST 、MULTISET 或 SET。
重要: 当声明集合变量时,必须指定 client 关键字。
类型和无类型集合变量
GBase 8s ESQL/C 支持以下两种集合变量:
类型集合变量指定集合中的元素和集合本身的数据类型。
无类型集合变量不指定集合类型或元素类型。
类型集合变量
类型集合变量提供集合的提供了集合的准确描述。
该声明指定集合的数据类型
(SET 、
MULTISET 或 LIST)以及集合变量的元素类型。
下图显示了三个类型集合变量的声明:
图: 类型集合变量示例
EXEC SQL BEGIN DECLARE SECTION;
client collection list(smallint not null)
list1;
client collection set(row(
x char(20),
y set(integer not null),
z decimal(10,2)) not null) row_set;
client collection multiset(set(smallint
not null)

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 214 -

not null) collection3;
EXEC SQL END DECLARE SECTION;
类型集合变量可以包含具有以下数据类型的元素:
任何内置数据类型
(例如 INTEGER 、
CHAR 、
BOOLEAN 和 FLOAT)
除 BYTE 、
TEXT 、SERIAL 或 SERIAL8 之外。
集合数据类型,例如 SET 和 LIST,以创建嵌套集合
未命名的行类型(已命名行类型不可用)
不透明数据类型
当指定集合变量的元素类型时,
请使用 SQL 数据类型而不是 GBase 8s ESQL/C 数据
类型。例如: 图 1中显示的 list1 变量的声明,使用 SQL SMALLINT 数据类型而不是
GBase 8s ESQL/C short 数据类型来声明 LIST 变量,
其元素是小整型。
同样,
对 CHAR 列
使用 SQL 语法声明 SET 变量,其元素都是字符字符串,如下所示:
client collection set(char(20) not null) set_var;
重要: 必须在集合变量的元素类型上指定非空约束。
已命名的行类型不能作为集合变量的元素类型。
但是,
您可以指定未命名行类型的元
素类型,其字段符合已命名行类型的那些字段。
例如:假定您的数据库具有已命名行类型 myrow,数据库表 mytable ,它们都如下
定义:
CREATE ROW TYPE myrow
(
a int,
b float
);
CREATE TABLE mytable
(
col1 int8,
col2 set(myrow not null)
);
可以为 mytable 的 col2 列定义集合变量,如下所示:
EXEC SQL BEGIN DECLARE SECTION;
client collection set(row(a int, b float) not null)
my_collection;
EXEC SQL END DECLARE SECTION;
只要两种数据类型兼容,就可以声明一个类型与集合列的元素类型不同的集合变量。
如果数据库服务器能够在这两个元素类型之间转换,则在返回获取的集合时,它将自动执
行此转换。
假设创建如下的 tab1 表:
CREATE TABLE tab1 (col1 SET(INTEGER NOT NULL))
可以声明类型集合变量,其元素类型符合(set_int)或其中之一的元素类型是兼容的

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 215 -

(set_float),如下所示:
EXEC SQL BEGIN DECLARE SECTION;
client collection set(float not null) set_float;
client collection set(integer not null) set_int;
EXEC SQL END DECLARE SECTION;

EXEC SQL declare cur1 cursor for select * from tab1;
EXEC SQL open cur1;
EXEC SQL fetch cur1 into:set_float;
EXEC SQL fetch cur1 into :set_int;
当它执行第一个 FETCH 语句时,
GBase 8s ESQL/C 客户端程序自动将列中的整数元
素转换为 set_float 主机变量中的浮点值。如果在第一次获取后更改主机变量,则 GBase
8s ESQL/C 程序只能生成类型不兼容错误。在之前的代码段中,第二个 FETCH 语句生成
类型不符错误,因为首次获取已经定义了元素类型为浮点。
在以下情况中使用类型集合变量:
当插入到派生表时(GBase 8s ESQL/C 需要知道是哪种类型)
当更改派生表中的元素时(GBase 8s ESQL/C 需要知道是哪种类型)
当需要服务器执行转型时。(GBase 8s ESQL/C 客户端将类型选项发送到数据库服务
器,它尝试执行请求的转型操作。如果不可能,数据库服务器返回错误。)
将类型集合变量的声明与集合列的数据类型完全匹配。然后可以在 SQL 语句
(INSERT 、DELETE 或 UPDATE)中或在集合派生表子句中直接使用此集合变量。
提示: 如果不知道您要访问的集合列的准确的数据类型,请使用无类型集合变量。
在单个声明行中,可以为同一类型的集合声明多个集合变量,如下所示:
EXEC SQL BEGIN DECLARE SECTION;
client collection multiset(integer not null) mset1, mset2;
EXEC SQL END DECLARE SECTION;
不能在一个声明行中为不同的集合类型声明集合变量。
无类型集合变量
无类型集合变量提供了集合的一般描述。此声明仅包含集合关键字和变量名称。
下行声明了三个无类型集合变量:
EXEC SQL BEGIN DECLARE SECTION;
client collection collection1, collection2;
client collection grades;
EXEC SQL END DECLARE SECTION;
无类型集合主机变量的优点是它在集合定义上提供更多的灵活性。
对于无类型集合变
量,在编译时不需要知道集合列的定义。相反,您可以在运行时会通过 SELECT 语句获得
集合列中的集合描述。
提示: 如果知道您要访问的集合列的准确的数据类型,请使用类型集合变量。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 216 -

要获得集合列的描述,执行 SELECT 语句将该列检索到无类型集合变量。数据库服
务器返回具有列数据的列(集合类型和元素类型)描述。GBase 8s ESQL/C 将集合列的定
义分配给无类型集合变量。
例如:假定将 a_coll 主机变量声明为无类型集合变量。如下所示:
EXEC SQL BEGIN DECLARE SECTION;
client collection a_coll;
EXEC SQL END DECLARE SECTION;
以下代码段在 INSERT 语句中使用集合变量之前,使用 SELECT 语句初始化具有
list_col 集合列(图 1 中定义)的定义的 a_coll 变量。
EXEC SQL allocate collection :a_coll;

/* select LIST column into the untyped collection variable
* to obtain the data-type information */
EXEC SQL select list_col into :a_coll from tab_list;

/* Insert an element at the end of the LIST in the untyped
* collection variable */
EXEC SQL insert into table(:a_coll) values (7);
要获得集合列的描述,您的应用程序必须验证集合列在选择列之前它里有数据。如果
表中没有行,则 SELECT 语句无法返回列数据或列描述,并且 GBase 8s ESQL/C 不会将
列描述分配给无类型集合变量。
可以使用无类型集合变量存储具有不同列定义的集合,只有您在 SQL 语句中使用变
量之前,将关联的集合列描述选择到集合变量。
重要: 在 SQL 语句中使用变量之前,必须获得无类型集合变量的集合列的定义。在
集合变量可以保存任何值之前,
必须使用 SELECT 语句从数据库中的集合列获取集合数据
类型的描述。因此,您无法直接将值插入或选择到无类型集合变量。
客户端集合
GBase 8s ESQL/C 应用程序声明集合变量名称,使用 ALLOCATE COLLECTION 语
句为其分配内存,然后在集合数据上执行操作。
要访问集合变量的元素,在 SELECT 、INSERT 、UPDATE 或 DELETE 语句的集
合派生表子句章指定变量。 GBase 8s ESQL/C 执行 SELECT 、INSERT 、UPDATE 或
DELETE 操作。当在集合派生表子句中包含客户端集合变量时,GBase 8s ESQL/C 不会将
这些语句发送到数据库服务器。
例如:GBase 8s ESQL/C 对 a_multiset 集合变量上执行以下 INSERT 操作:
EXEC SQL BEGIN DECLARE SECTION;
client collection multiset(integer not null) a_multiset;
EXEC SQL END DECLARE SECTION;
EXEC SQL insert into table(:a_multiset) values (6);
当 SQL 语句包含集合变量时,它具有以下语法限制:

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 217 -

只能使用集合派生表子句和 SELECT 、INSERT 、UPDATE 或 DELETE 语句访问
客户端集合的元素。
INSERT 语句的 VALUES 子句中不能具有 SELECT 、EXECUTE FUNCTION 或
EXECUTE PROCEDURE 语句。
不能包含 WHERE 子句
不能包含表达式
不能使用滚动游标
集合的内存管理
GBase 8s ESQL/C 不会对集合变量自动分配或释放内存。您必须显式管理分配给集
合变量的内存。
使用以下 SQL 语句管理类型和无类型集合主机变量的内存:
ALLOCATE COLLECTION 为指定的集合变量分配内存。
集合变量可以是类型的或无类型集合的。ALLOCATE COLLECTION 语句将
SQLCODE(sqlca.sqlcode)设置为零(如果内存分配成功)和负数(如果内存分配失
败)。
DEALLOCATE COLLECTION 语句为指定的集合变量释放内存。
在使用 DEALLOCATE COLLECTION 语句释放集合变量的内存后,
可以重新使用集
合变量。
重要:
必须显式释放分配给集合变量的内存。
使用 DEALLOCATE COLLECTION 语
句释放内存。
以下代码段声明 a_set 主机变量作为类型集合,并为此变量分配内存,然后释放此变
量的内存。
EXEC SQL BEGIN DECLARE SECTION;
client collection set(integer not null) a_set;
EXEC SQL END DECLARE SECTION;


EXEC SQL allocate collection :a_set;


EXEC SQL deallocate collection :a_set;
ALLOCATE COLLECTION 语句为集合变量和集合数据分配内存。
当 DEALLOCATE COLLECTION 语句失败时,是因为集合上的游标仍是打开的,会
返回错误消息,该错误不会被跟踪。
集合变量上的操作

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 218 -

GBase 8s 支持通过 SELECT 、UPDATE 、INSERT 和 DELETE 语句访问集合列。
例如:
SELECT 语句可以检索集合的所有元素,
UPDATE 语句可以将集合中所有的元素更
改为单个值。
提示: GBase 8s 直接使用 SELECT 语句的 WHERE 子句中的 IN 谓词只能访问集
合列的内容。IN 谓词只在简单集合(集合的元素是不复杂的类型)中有用。
SELECT 、INSERT 、UPDATE 和 DELETE 语句不能访问表中集合列的元素。要访
问集合列中的元素,
GBase 8s ESQL/C 应用程序在集合变量中建立子表,
称为集合派生表。
为了组成集合派生表,GBase 8s ESQL/C 应用程序访问集合变量的元素作为表的行。
本节讨论以下主题,如何在 GBase 8s ESQL/C 应用程序中使用集合派生表访问集合
列:
使用 SQL 语句中的集合派生表访问集合主机变量
具有集合列的集合主机变量
插入元素到集合主机变量中
从集合主机变量中选择元素
更新集合主机变量中的元素
指定集合主机变量的元素值
删除集合主机变量中的元素
访问具有集合主机变量的嵌套集合
集合上的集合派生表子句
集合派生表子句允许您指定集合主机变量作为表名。
该子句具有以下语法:
TABLE(:coll_var)
在此示例中,coll_var 是集合主变量。它可以是类型或无类型集合主机变量,但是
在它出现在集合派生表子句之前,
必须声明并已在 GBase 8s ESQL/C 应用程序中分配内存。

访问集合变量
在 SQL 语句中,GBase 8s ESQL/C 应用程序在表名的位置指定集合派生表,以在集
合主机变量上执行下列操作:
可以使用 INSERT 的 INTO 关键字或 PUT 语句后的集合派生表子句将元素插入到
集合变量中。
可以使用 SELECT 语句的 FROM 子句中的集合派生表子句从集合主机变量中选择
一个元素。
可以在 UPDATE 语句的 UPDATE 关键字之后使用集合派生表子句(而不是表名)
更新集合主机变量中的所有或某些值。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 219 -

可以在 DELETE 语句的 FROM 关键字之后,使用集合派生表子句从集合主机变量
删除所有或某些元素。
提示: 如果您仅需要插入或更改具有文字值的集合列,则不必使用集合主机变量。相
反,
可以在 INSERT 语句的 INTO 子句或 UPDATE 语句的 SET 子句中显式列出文字集
合值。
集合主机变量包含有效元素后,可以使用主机变量的更新集合列。
区分列和集合变量
当在 SQL 语句(如 SELECT 、INSERT 或 UPDAT)中使用集合派生表子句与集合
主机变量时,该语句不会发送到数据库服务器进行处理。相反,GBase 8s ESQL/C 处理该
语句。因此,数据库服务器执行的某些语法检查在包含集合派生表子句的 SQL 语句上未
完成。
尤其是,
GBase 8s ESQL/C 预处理程序无法区分列名和主机变量。
因此,
在 UPDATE
或 INSERT 语句中使用集合派生表子句时,您必须子在以下子句中使用有效的主机变量:

UPDATE 语句的 SET 子句
INSERT 语句的 VALUES 子句
初始化集合变量
您必须始终通过在其中选择集合列来初始化无类型集合变量。无论要对无类型集合
变量执行什么操作,都必须执行 SELECT 语句。
重要: 将集合列选择为无类型集合变量,为 GBase 8s ESQL/C 提供了集合声明的描
述。
可以通过将集合列选择到集合变量中来初始化集合变量,构建 SELECT 语句如下:
在选择列表中指定集合列的名称。
在 INTO 子句中指定集合主机变量。
在 FROM 子句中指定表或视图名(而不是集合派生表子句)
可以通过执行使用集合派生表语法的 INSERT 语句来初始化类型集合变量。不需要
在 INSERT 或 UPDATE 前初始化类型集合变量,因为 GBase 8s ESQL/C 具有集合变量
的描述。
例如:假定您使用下图中的语句创建 tab_list 和 tab_set 表:
图: 具有集合列的示例表
EXEC SQL create table tab_list
(list_col list(smallint not null));
EXEC SQL create table tab_set
(
id_col integer,
set_col set(integer not null)

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 220 -

);
以下代码段使用名为 a_set 的类型集合变量访问 set_col 列:
EXEC SQL BEGIN DECLARE SECTION;
client collection set(integer not null) a_set;
EXEC SQL END DECLARE SECTION;

EXEC SQL allocate collection :a_set;
EXEC SQL select set_col into :a_set from tab_set
where id_col = 1234;
当使用类型集合主机变量时,
集合列的描述
(集合类型和元素类型)
与相应的类型集
合主机变量的描述匹配。如果数据类型不匹配,则数据库服务器可以执行一个转换。由于
a_set 主机变量具有与 set_col 列相同的集合类型(SET)元素类型(INTEGER),索引
前面的代码段中的 SELECT 语句可以成功地检索 set_col 列。
以下 SELECT 语句成功,因为数据库服务器将 list_col 列转型为 a_set 主机变量中
的集合,并丢弃任何重复值:
/* This SELECT generates an error */
EXEC SQL select list_col into :a_set from tab_list;
可以将任何类型的集合选择到无类型集合主变量中。以下代码段,使用无类型集合主
机变量访问图 1中定义的 list_col 和 set_col 列:
EXEC SQL BEGIN DECLARE SECTION;
client collection a_collection;
EXEC SQL END DECLARE SECTION;

EXEC SQL allocate collection :a_collection;
EXEC SQL select set_col into :a_collection
from tab_set
where id_col = 1234;


EXEC SQL select list_col into :a_collection
from tab_list
where list{6} in (list_col);
这段代码中的两个 SELECT 语句都可以成功地将集合列检索到 a_collection 主机
变量中。
初始化集合主机变量后,可以使用集合派生表子句 select 、update 或 delete 集合中
的现有元素,或者向集合中插入其它元素。
插入元素到集合变量中
要向集合变量中插入一个或多个元素,请在 INTO 关键字之后使用具有集合派生表
子句的 INSERT 语句。集合派生表子句标识要插入元素的集合变量。将 INSERT 语句和
集合派生表子句与游标相关联,以将多个元素插入到集合变量中。
限制: 不能在 VALUES 子句中使用表达式,也不能使用 WHERE 子句。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 221 -

插入一个元素
INSERT 语句和集合派生表子句允许您往集合中插入一个元素。
GBase 8s ESQL/C 将 VALUES 子句指定的值插入到集合派生表子句指定的集合变
量中。
提示: 将元素插入到客户端集合变量时,不能在 INSERT 的 VALUES 子句中指定
SELECT 、EXECUTE FUNCTION 、或 EXECUTE PROCEDURE 语句。
向 SET 和 MULTISET 集合中插入元素
对于 SET 和 MULTISET 集合,新元素的位置时未定义的,因为,这些集合的元素
不具有顺序位置。假定表 readings 具有以下声明:
CREATE TABLE readings
(
dataset_id INT8,
time_dataset MULTISET(INT8 NOT NULL)
);
要访问 time_dataset 列, 类型 GBase 8s ESQL/C 主机变量 time_vals 具有以下声
明:
EXEC SQL BEGIN DECLARE SECTION;
client collection multiset(int8 not null) time_vals;
ifx_int8_t an_int8;
EXEC SQL END DECLARE SECTION;
以下 INSERT 语句插入新 MULTISET 元素 1,423,231 到 time_vals 中:
EXEC SQL allocate collection :time_vals;
EXEC SQL select time_dataset into :time_vals
from readings
where dataset_id = 1356;
ifx_int8cvint(1423231, &an_int8);
EXEC SQL insert into table(:time_vals) values (:an_int8);
向 LIST 集合中插入元素
LIST 集合的元素具有有序位置。如果集合是 LIST 类型,则可以使用 INSERT 语句
的 AT 子句来指定要添加新元素的列表中的位置。假设表 rankings 具有以下声明:
CREATE TABLE rankings
(
item_id INT8,
item_rankings LIST(INTEGER NOT NULL)
);
要访问 item_rankings 列,类型 GBase 8s ESQL/C 主机变量 rankings 具有以下声
明:
EXEC SQL BEGIN DECLARE SECTION;
client collection list(integer not null) rankings;
int an_int;
EXEC SQL END DECLARE SECTION;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 222 -

以下 INSERT 语句将新元素 9 添加为 rankings 的第三个元素:
EXEC SQL allocate collection :rankings;
EXEC SQL select rank_col into :rankings from results;
an_int = 9;
EXEC SQL insert at 3 into table(:rankings) values (:an_int);
假设在插入之前,rankings 包含元素 {1,8,4,5,2}。那么插入之后,该变量包含元
素 {1,8,9,4,5,2}。
如果未指定 AT 子句,那么 INSERT 在 LIST 集合的末尾添加新元素。
插入多个元素
包含具有集合派生表子句的 INSERT 语句的插入游标允许您向集合变量中插入许多
元素。
要插入元素,请按以下步骤操作:
在 GBase 8s ESQL/C 程序中创建一个客户端集合变量。
使用 DECLARE 语给集合变量声明插入游标,并使用 OPEN 语句打开游标。
使用 PUT 语句和 FROM 子句将一个或多个元素插入集合变量。
使用 CLOSE 语句关闭插入游标,如果不再需要游标,则使用 FREE 语句释放它。
在集合变量包含所有元素后,可以在表名上使用 UPDATE 语句或 INSERT 语句来
包含集合列(SET 、MULTISET 或 LIST)中集合变量的内容。
提示: 可以使用 INSERT 语句而不是插入游标将元素一次性插入到集合变量中。但
是,插入游标对于大型数据的插入更有效。
为集合变量声明插入游标
插入游标允许您在集合中插入一个或多个元素。
要为集合变量声明插入游标,请在与游标相关联的 INSERT 语句中包含集合派生表
子句。集合变量的插入游标具有以下限制:
它必须是顺序游标,DECLARE 语句不能指定 SCROLL 关键字。
不能是保持游标;DECLARE 语句不能指定 WITH HOLD 游标的特性。
如果需要使用输入参数,必须准备 INSERT 语句并在 DECLARE 语句中指定准备好
的语句标识符。
可以使用输入参数指定 INSERT 语句的 VALUES 子句中的值。
以下 DECLARE 语句为 a_list 变量声明 list_curs 插入游标:
EXEC SQL prepare ins_stmt from
'insert into table values';
EXEC SQL declare list_curs cursor for ins_stmt;
EXEC SQL open list_curs using :a_list;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 223 -

然后使用 PUT 子句指定要插入的值。有关包含此语句的代码段,请参阅图 1。
重要:
无论何时在集合派生表中的集合主机变量的 PREPARE 语句中使用问号
(?)

如果执行 DESCRIBE 语句,
则必须在 OPEN 语句之后执行。
在 OPEN 语句之前,
GBase
8s ESQL/C 不知道集合行的内容。
集合派生表中集合变量的名称
以下 DECLARE 语句为 a_list 变量声明 list_curs2 插入游标:
EXEC SQL prepare ins_stmt2 from
'insert into table values';
EXEC SQL declare list_curs2 cursor for ins_stmt2;
EXEC SQL open list_curs2 using :a_list;
while (1)
{
EXEC SQL put list_curs2 from :an_element;



}
OPEN 语句的 USING 子句指定集合变量的名称。
然后可以使用 PUT 语句指定要插
入的值。
声明插入游标之后,可以使用 OPEN 语句打开它。一旦相关联的插入游标打开,则
可以将元素插入到集合变量中。
将元素放入到插入游标中
要一次性将元素放入到插入游标中,使用 PUT 语句和 FROM 子句。
PUT 语句标识与集合变量相关联的插入游标。FROM 子句标识要插入到游标的元素
值。FROM 子句中任何主机变量的数据类型必须与集合的元素类型相符合。
要指示以后由 PUT 语句的 FROM 子句提供集合元素,请在 INSERT 语句的
VALUES 子句中使用输入参数。您可以使用 PUT 语句与静态 DECLARE 语句或
PREPARE 语句之后插入游标。以下示例在静态 DECLARE 语句之后使用 PUT 。
EXEC SQL DECLARE list_curs cursor FOR INSERT INTO table
(:alist);
EXEC SQL open list_curs;
EXEC SQL PUT list_curs from :asmint;
DECLARE 语句中不能显示输入参数。
下图包含一个代码片段,
演示如何将元素插入到集合变量 a_list 中,
然后使用此新集
合更改 tab_list 表(图 1中定义)的 list_col 列。
图: 将许多元素插入到集合变量中
EXEC SQL BEGIN DECLARE SECTION;
client collection list(smallint not null) a_list;
int a_smint;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 224 -

EXEC SQL END DECLARE SECTION;


EXEC SQL allocate collection :a_list;

/* Step 1: declare the insert cursor on the collection variable */
EXEC SQL prepare ins_stmt from
'insert into table values';
EXEC SQL declare list_curs cursor for ins_stmt;
EXEC SQL open list_curs using :a_list;

/* Step 2: put the LIST elements into the insert cursor */
for (a_smint=0; a_smint<10; a_smint++)
{
EXEC SQL put list_curs from :a_smint;
};
/* Step 3: save the insert cursor into the collection variable
EXEC SQL close list_curs;

/* Step 4: save the collection variable into the LIST column */
EXEC SQL insert into tab_list values (:a_list);

/* Step 5: clean up */
EXEC SQL deallocate collection :a_list;
EXEC SQL free ins_stmt;
EXEC SQL free list_curs;
在图 1中,
访问 a_list 变量的第一个语句是 OPEN 语句。
因此,
在代码中,
GBase 8s
ESQL/C 必须可以从变量声明中确定 a_list 变量的数据类型。
因为 a_list 主机变量是类
型集合变量,所以 GBase 8s ESQL/C 可以从变量声明中变量的数据类型。但是,如果在无
类型集合变量中声明 a_list,
则在执行 DECLARE 之前需一个 SELECT 语句来返回关联
集合列的定义。
当使用 PUT 语句将其插入到游标中时,GBase 8s ESQL/C 会自动将插入游标的内容
保存在集合变量中。
释放游标资源
CLOSE 语句显式释放分配给插入游标的资源。但是,游标 ID 仍存在,因此可以使
用 OPEN 语句重新打开它。FREE 语句显式释放游标 ID。要重新使用游标,必须使用
DECLARE 语句再次声明该游标。
FLUSH 语句不会影响与集合变量相关联的插入游标。
从集合变量选择数据
使用集合派生表子句的 SELECT 语句允许您从集合变量中选择元素。
集合派生表子句标识要从中选择元素的集合变量。客户端集合变量(具有集合派生表
子句)的 SELECT 语句具有以下限制:

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 225 -

SELECT 的选择列表不能包含表达式。
选择列表必须是一个星号(*)。
选择列表中的列名必须是个单个列名称。
这些列不能使用 database@server:table.column 语法。
以下 SELECT 子句和选项是不允许的:GROUP BY 、HAVING 、INTO TEMP 、
ORDER BY 、WHERE 、WITH REOPTIMIZATION。
FROM 子句没有规定进行连接。
SELECT 语句和集合派生表子句允许您在集合变量上执行以下操作:
从集合选择一个元素
使用具有集合派生表子句的 SELECT 语句
从集合选择一行元素
使用具有集合派生表子句和行变量的 SELECT 语句Use the SELECT
从集合选择一个或多个元素
将 SELECT 语句和集合派生表子句与一个游标相关联,以为集合变量声明一个选择
游标。
选择一个元素
SELECT 语句和集合派生表子句允许您将一个元素选择到集合中。
INTO 子句标识存储从集合变量中选择的元素值的变量。INTO 子句中的主机变量的
数据类型必须与集合的元素类型兼容。
以下代码片段仅使用名为 a_set 的集合主机变量从 set_col 列(参见图 1)中仅选
择一个元素:
EXEC SQL BEGIN DECLARE SECTION;
client collection set(integer not null) a_set;
int an_element, set_size;
EXEC SQL END DECLARE SECTION;

EXEC SQL allocate collection :a_set;
EXEC SQL select set_col, cardinality(set_col)
into :a_set, :set_size from tab_set
where id_col = 3;
if (set_size == 1)
EXEC SQL select * into :an_element from table(:a_set);
重要:
当您确定 SELECT 语句只返回一个元素时,
请使用此形式的 SELECT 语句。
如果 SELECT 语句返回多个元素,则 GBase 8s ESQL/C 返回错误。如果不指定集合中的
元素数或者您知道集合包含多个元素,请使用选择游标访问元素。
如果集合的元素本身是一个复杂类型(集合或行类型),则集合是一个嵌套集合。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 226 -

选择一行元素
可以将集合中的一整行元素选择到行类型主机变量中。
INTO 子句标识一个行变量,用于存储从集合变量中选择的行元素。
以下代码片段从 set_col 列中选择一行到行类型主机变量 a_row 中:
EXEC SQL BEGIN DECLARE SECTION;
client collection set(row(a integer) not null) a_set;
row (a integer) a_row;
EXEC SQL END DECLARE SECTION;

EXEC SQL select set_col into :a_set from tab1
where id_col = 17;
EXEC SQL select * into :a_row from table(:a_set);
选择多个元素
包含具有集合派生表子句的 SELECT 语句的选择游标允许您从集合变量中选择许多
元素。
要选择元素,请执行这些步骤:
在 GBase 8s ESQL/C 程序中创建客户端集合变量。
使用 DECLARE 语句为集合变量声明选择游标,并使用 OPEN 语句打开此游标。
使用 FETCH 语句和 INTO 子句从集合变量中获取元素。
如果必要,对获得的数据执行更改或删除,并将已修改的集合变量保存在集合列中。

使用 CLOSE 语句关闭选择游标,如果不再需要此游标,使用 FREE 语句释放它。
为集合变量声明选择游标
要为集合变量声明选择游标,使用与游标相关联的 SELECT 语句包含集合派生表子
句。此选择游标的 DECLARE 具有以下限制:
选择游标是更新游标。
DECLARE 语句不能包含指定只读游标模式的 FOR READ ONLY 子句。
选择游标必须是顺序游标。
DECLARE 语句不能指定 SCROLL 或 WITH HOLD 游标特征。
当为集合变量声明选择游标时,
SELECT 语句的集合派生表子句必须包含集合变量名
称。例如:以下 DECLARE 语句对集合变量声明选择游标 a_set:
EXEC SQL BEGIN DECLARE SECTION;
client collection set(integer not null) a_set;
EXEC SQL END DECLARE SECTION;



GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 227 -

EXEC SQL declare set_curs cursor for
select * from table(:a_set);
要从集合变量中选择一个或多个元素,使用带 INTO 子句的 FETCH 语句。
如果想要修改集合变量的元素,
使用 FOR UPDATE 关键字将选择游标声明为更新游
标。
然后使用 DELETE 和 UPDATE 的 WHERE CURRENT OF 子句删除或更改集合的元
素。
从选择游标获取元素
要一次性从集合变量中一次性获取元素,请使用 FETCH 语句和 INTO 子句。
FETCH 语句标识与集合变量相关联的选择游标。
INTO 子句标识从集合变量中获取
的元素值的主变量。INTO 子句的主机变量的数据类型必须与集合的元素类型相匹配。
下图包含一个代码片段,演示如何将 set_col 列(参见图 1)中的所有元素选择到名
为 a_set 的类型集合主机变量,然后一次性从 a_set 集合变量获取这些元素。
图: 从集合主机变量中选择许多元素
EXEC SQL BEGIN DECLARE SECTION;
client collection set(integer not null) a_set;
int an_element, set_size;
EXEC SQL END DECLARE SECTION;
int an_int


EXEC SQL allocate collection :a_set;
EXEC SQL select set_col, cardinality(set_col)
into :a_set from tab_set
from tab_set where id_col = 3;

/* Step 1: declare the select cursor on the host variable */
EXEC SQL declare set_curs cursor for
select * from table(:a_set);
EXEC SQL open set_curs;

/* Step 2: fetch the SET elements from the select cursor */
for (an_int=0; an_int{
EXEC SQL fetch set_curs into :an_element;



};
EXEC SQL close set_curs;

/* Step 3: update the SET column with the host variable */
EXEC SQL update tab_list SET set_col = :a_set
where id_col = 3

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 228 -


EXEC SQL deallocate collection :a_set;
EXEC SQL free set_curs;
更改集合变量
在使用集合列初始化集合主机变量后,
可以使用具有集合派生表子句的 UPDATE 语
句更改集合中的元素。集合派生表子句标识要更改元素的集合变量。
UPDATE 语句和集合派生表子句允许您对集合变量执行以下操作:
将集合中的所有元素更改为同一值。
使用 UPDATE 语句(不带 WHERE CURRENT OF 子句)在 SET 子句中指定派生
列名。
更改集合中的特定元素。
必须为集合变量声明更新游标,并使用带有 WHERE CURRENT OF 子句的
UPDATE 。
这两种形式的 UPDATE 语句都不能包含 WHERE 子句。
更改所有元素
不能在具有集合派生表子句的 UPDATE 语句上包含 WHERE 子句。因此,集合变
量上的 UPDATE 语句将集合中的所有元素设置为您在 SET 子句中指定的值。
不需要更新
游标来更改集合中的所有元素。
例如,
以下 UPDATE 语句将 a_list GBase 8s ESQL/C 集合变量中的所有元素更改为
值 16:
EXEC SQL BEGIN DECLARE SECTION;
client collection list(smallint not null) a_list;
int an_int;
EXEC SQL END DECLARE SECTION;


EXEC SQL update table(:a_list) (list_elmt)
set list_elmt = 16;
在此示例中,派生列 list_elmt 提供别名以标识 SET 子句中集合的元素。
更改一个元素
要更改集合中的一个特定元素,请为集合主机变量声明更新游标。
集合变量的更新游标是用 FOR UPDATE 关键字声明的选择游标。
该更新游标允许您
顺序划过集合中的元素并使用 UPDATE...WHERE CURRENT OF 语句更新当前的元素。
要更改元素,请执行这些步骤:
在 GBase 8s ESQL/C 程序中创建客户端集合变量。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 229 -

使用 DECLARE 语句和 FOR UPDATE 子句为集合变量声明更新游标,并使用
OPEN 语句打开此游标。
缺省情况下,集合变量上的选择游标支持更新。
使用 FETCH 语句和 INTO 子句从集合变量中获取一个或多个元素。
使用 UPDATE 语句和 WHERE CURRENT OF 子句更改获取的数据。
保存集合列中已修改的集合变量。
使用 CLOSE 语句关闭选择游标,如果不再需要此游标,使用 FREE 语句释放它。
应用程序必须将更改游标放到要更改的元素上,然后使用 UPDATE...WHERE
CURRENT OF 更改此值。
下图中的 GBase 8s ESQL/C 程序使用更新游标更改集合变量 a_set 中的一个元素,
然后更改 tab_set 表(请参阅图 1)的 set_col 列。
图: 更改集合主机变量中的一个元素
EXEC SQL BEGIN DECLARE SECTION;
int an_element;
client collection set(integer not null) a_set;
EXEC SQL END DECLARE SECTION;

EXEC SQL allocate collection :a_set;
EXEC SQL select set_col into :a_set from tab_set
where id_col = 6;

EXEC SQL declare set_curs cursor for
select * from table(:a_set)
for update;

EXEC SQL open set_curs;
while (SQLCODE != SQLNOTFOUND)
{
EXEC SQL fetch set_curs into :an_element;
if (an_element = 4)
{
EXEC SQL update table(:a_set)(x)
set x = 10
where current of set_curs;
break;
}
}

EXEC SQL close set_curs;

EXEC SQL update tab_set set set_col = :a_set
where id_col = 6;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 230 -


EXEC SQL deallocate collection :a_set;
EXEC SQL free set_curs;
指定元素值
可以指定以下任何值作为在集合变量中的元素:
文字值
可以直接为集合列指定文字值,而不是首先使用集合变量。
GBase 8s ESQL/C 主机变量
主机变量必须包含数据类型与集合的元素类型相符的值。
不能包含复杂表达式来直接指定值。
文字值作为元素
可以使用文字值指定集合变量的元素。文字值必须具有与集合元素类型相符的数据类
型。
例如,以下 INSERT 语句向 SET(INTEGER NOT NULL) 主机变量 a_set 插入文字
整数:
EXEC SQL insert into table(:a_set) values (6);
以下 UPDATE 语句使用派生列名
(an_element)
将集合变量 a_set 中的所有元素更
改为 19:
EXEC SQL update table(:a_set) (an_element)
set an_element = 19;
以下 INSERT 语句向名为 a_set2 的 LIST(CHAR(5)) 主机变量中插入带引号的字
符串:
EXEC SQL insert into table(:a_set2) values ('abcde');
下列 INSERT 语句向名为 nested_coll 的 SET(LIST(INTEGER NOT NULL) 主机变
量中插入文字集合:
EXEC SQL insert into table(:nested_coll)
values (list{1,2,3});
提示:
集合变量的文字集合的语法与集合列的文字集合语法不同。
集合变量不需要带
引号。
以下 UPDATE 语句将 nested_coll 集合变量更改为新的文字集合值:
EXEC SQL update table(:nested_coll) (a_list)
set a_list = list{1,2,3};
提示:
如果您只需要插入或更改集合列为文字值,
则不需要使用集合主机变量。
相反,
可以在 INSERT 语句的 INTO 子句或 UPDATE 语句的 SET 子句中显式地列出作为文
字集合的文字值。
ESQL/C 主机变量作为元素

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 231 -

可以使用 GBase 8s ESQL/C 主机变量指定集合变量的一个元素。
该主机变量必须使用与集合的元素类型相匹配的数据类型声明,并且必须包含与其符
合的值。
例如:
以下 INSERT 语句使用主机变量将一个值插入到前面示例中的 a_set 变量
中:
an_int = 6;
EXEC SQL insert into table(:a_set) values (:an_int);
要插入多个值到集合变量,可以对每个值使用 INSERT 语句货值可以声明插入游标
并使用 PUT 语句。
以下 UPDATE 语句使用主机变量将 a_sett 集合中的所有元素更改为值 4:
an_int = 4;
EXEC SQL update table(:a_set) (an_element)
set an_element = :an_int;
要将多个值更改到集合变量,可以声明更新游标并使用 UPDATE 语句的 WHERE
CURRENT OF 子句。
删除集合变量中的元素
使用集合列初始化的集合主机变量后,可以使用 DELETE 语句和集合派生表子句删
除集合变量中的元素。集合派生表子句标识要删除元素的集合变量。
DELETE 语句和集合派生表子句允许您对集合变量执行以下操作:
删除集合中的所有元素。
使用 DELETE 语句(不带 WHERE CURRENT OF 子句)。
删除集合中的特定元素。
必须为集合变量声明更新游标,并使用带 WHERE CURRENT OF 子句的 DELETE。

这两种形式的 DELETE 语句都不能包含 WHERE 子句。
删除所有元素
不能在具有集合派生表子句的 DELETE 语句中包含 WHERE 语句。因此,集合变
量的 DELETE 语句删除集合中的所有元素。 删除集合的所有元素不需要更新游标。
例如,以下 DELETE 移除 a_list GBase 8s ESQL/C 集合变量中的所有元素:
EXEC SQL BEGIN DECLARE SECTION;
client collection list(smallint not null) a_list;
EXEC SQL END DECLARE SECTION;


EXEC SQL delete from table(:a_list);
删除一个元素
要删除集合中的一个特定元素,请对集合主机变量声明更新游标。集合变量的更新

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 232 -

游标是用 FOR UPDATE 关键字声明的选择游标。该更新游标允许您顺序划过集合中的元
素并使用 DELETE...WHERE CURRENT OF 语句删除当前的元素。
要删除特定的元素,请按照更新特定元素的步骤执行。在这些步骤中,将
UPDATE...WHERE CURRENT OF 语句替换为 DELETE...WHERE CURRENT OF 语句。
应用程序必须将更改游标放到要删除的元素上,然后使用 DELETE...WHERE
CURRENT OF 删除此值。
下图中的 GBase 8s ESQL/C 程序使用更新游标和具有 WHERE CURRENT OF 子句
的 DELETE 语句删除 tab_set 表(请参阅图 1)的 set_col 列的元素。
EXEC SQL BEGIN DECLARE SECTION;
client collection set(integer not null) a_set;
int an_int, set_size;
EXEC SQL END DECLARE SECTION;


EXEC SQL allocate collection :a_set;
EXEC SQL select set_col, cardinality(set_col)
into :a_set, :set_size
from tab_set
where id_col = 6;

EXEC SQL declare set_curs cursor for
select * from table(:a_set)
for update;

EXEC SQL open set_curs;
while (i < set_size)
{
EXEC SQL fetch set_curs into :an_int;
if (an_int == 4)
{
EXEC SQL delete from table(:a_set)
where current of set_curs;
break;
}
i++;
}
EXEC SQL close set_curs;
EXEC SQL free set_curs;

EXEC SQL update tab_set set set_col = :a_set
where id_col = 6;

EXEC SQL deallocate collection :a_set;
假定行中的 id_col 值为 6,则 set_col 列在该代码执行之前包含值 {1,8,4,5,2}。在
DELETE...WHERE CURRENT OF 语句执行之后,此集合变量包含元素 {1,8,5,2}。代码末

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 233 -

尾的 UPDATE 语句将更改的集合保存到数据库的 set_col 列中。若没有此 UPDATE 语
句,则集合列将不会删除元素 4。
访问嵌套集合
GBase 8s 支持将嵌套集合作为列类型。嵌套集合是元素类型是另一个集合的集合列。
例如:下图中的代码段创建表 tab_setlist ,其列是嵌套集合。
图: 具有嵌套集合的示例列
EXEC SQL create table tab_setlist
( setlist_col set(list(integer not null));
setlist_col 列是一个集合,每个元素是一个列表。该嵌套集合类似于具有集合元素的
Y 轴和列表元素的 X 轴的二维数组。
从嵌套集合选择值
要从嵌套集合选择值,您必须为每个级别的集合声明集合变量和选择游标。
以下代码段使用嵌套集合变量 nested_coll 和集合变量 list_coll 来选择嵌套集合列
setlist_col 中的最低级别元素。
EXEC SQL BEGIN DECLARE SECTION;
client collection set(list(integer not null) not null) nested_coll;
client collection list(integer not null) list_coll;
int an_element;
EXEC SQL END DECLARE SECTION;
int num_elements = 1;
int an_int;
int keep_fetching = 1;


EXEC SQL allocate collection :nested_coll;
EXEC SQL allocate collection :list_coll;

/* Step 1: declare the select cursor on the SET collection variable */
EXEC SQL declare set_curs2 cursor for
select * from table(:nested_coll);

/* Step 2: declare the select cursor on the LIST collection variable */
EXEC SQL declare list_curs2 cursor for
select * from table(:list_coll);

/* Step 3: open the SET cursor */
EXEC SQL open set_curs2;

while (keep_fetching)
{

/* Step 4: fetch the SET elements into the SET insert cursor */
EXEC SQL fetch set_curs2 into :list_coll;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 234 -


/* Open the LIST cursor */
EXEC SQL open list_curs2;

/* Step 5: put the LIST elements into the LIST insert cursor */
for (an_int=0; an_int<10; an_int++)
{
EXEC SQL fetch list_curs2 into :an_element;



};
EXEC SQL close list_curs2;
num_elements++;

if (done_fetching(num_elements))
{
EXEC SQL close set_curs2;
keep_fetching = 0;
}
};
EXEC SQL free set_curs2;
EXEC SQL free list_curs2;

EXEC SQL deallocate collection :nested_coll;
EXEC SQL deallocate collection :list_coll;:
向嵌套集合中插入值
要将文字值插入到集合列的集合变量中,请为此元素类型指定文字集合。
不需要对实际的集合类型指定构建关键字。以下类型集合主机变量可以访问
tab_setlist 表的 setlist_col 列:
EXEC SQL BEGIN DECLARE SECTION;
client collection set(list(integer not null) not null)
nested_coll;
EXEC SQL END DECLARE SECTION;

EXEC SQL allocate collection nested_coll;
以下代码片段,
将文字值插入到 nested_coll 集合变量中,
然后更改 setlist_col 列
(在
图 1 中定义):
EXEC SQL insert into table(:nested_coll)
values (list{1,2,3,4});
EXEC SQL insert into tab_setlist values (:nested_coll);
要向嵌套集合中插入非文字值,
必须为集合的每一级声明集合变量和插入游标。
例如:
以下代码片段使用嵌套集合变量 nested_coll,向嵌套集合列 setlist_col 插入新元素:
EXEC SQL BEGIN DECLARE SECTION;

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 235 -

client collection set(list(integer not null) not null) nested_coll;
client collection list(integer not null) list_coll;
int an_element;
EXEC SQL END DECLARE SECTION;
int num_elements = 1;
int keep_adding = 1;
int an_int;


EXEC SQL allocate collection :nested_coll;
EXEC SQL allocate collection :list_coll;

/* Step 1: declare the insert cursor on the SET collection variable */
EXEC SQL declare set_curs cursor for
insert into table(:nested_coll) values;

/* Step 2: declare the insert cursor on the LIST collection variable */
EXEC SQL declare list_curs cursor for
insert into table(:list_coll) values;

/* Step 3: open the SET cursor */
EXEC SQL open set_curs;

while (keep_adding)
{

/* Step 4: open the LIST cursor */
SQL open list_curs;

/* Step 5: put the LIST elements into the LIST insert cursor */
for (an_int=0; an_int<10; an_int++)
{
an_element = an_int * num_elements;
EXEC SQL put list_curs from :an_element;



};
EXEC SQL close list_curs;
num_elements++;

/* Step 6: put the SET elements into the SET insert cursor */
EXEC SQL put set_curs from :list_coll;
if (done_adding(num_elements)
{
EXEC SQL close set_curs;
keep_adding = 0;
}
};

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 236 -

EXEC SQL free set_curs;
EXEC SQL free list_curs;

/* Step 7: insert the nested SET column with the host variable */
EXEC SQL insert into tab_setlist values (:nested_coll);

EXEC SQL deallocate collection :nested_coll;
EXEC SQL deallocate collection :list_coll;
集合列上的操作
集合变量存储集合的元素。但是,它与数据库列没有固定的连接。必须使用 INSERT
或 UPDATE 语句显式将集合变量的元素保存到集合列中。
可以使用 SELECT 、UPDATE 、INSERT 和 DELETE 语句访问集合列(SET 、
MULTISET 或 LIST),如下所示:
SELECT 语句从集合列获取所有元素。
INSERT 语句将新集合插入到集合列中。
对表或视图名使用 INSERT 语句,在 VALUES 子句中指定集合变量。
UPDATE 语句使用新值更新集合列中整个集合。
对表或视图名使用 UPDATE ,在 SET 子句中指定集合变量。
从集合列选择
要选择集合列中的所有元素,在 SELECT 语句的选择列表中指定集合列。如果将集
合主机变量放到 SELECT 语句的 INTO 子句中,
则可以从 GBase 8s ESQL/C 应用程序访
问这些元素。
插入和更改集合列
INSERT 和 UPDATE 语句支持集合列,如下所示:
要将集合的元素插入到集合列,在 INSERT 语句的 VALUES 子句中指定新的元素。

要更改集合列的整个集合,
请在 UPDATE 语句的 SET 子句中指定新元素。
UPDATE
语句必须指定派生列名来为此元素创建标识符。
然后在 SET 子句中使用派生列名标识要分
配新元素值的位置。
在 INSERT 语句的 VALUES 子句或 UPDATE 语句的 SET 子句中,
元素值可以是
以下任一一种格式:
GBase 8s ESQL/C 集合主机变量
文字集合变量
要为集合列表示文字值,请指定文字集合值。您创建一个文字集合值,使用 SET 、
MULTISET 或 LIST 关键字引入该值,并以包含大括号的逗号分隔列表提供字段值。您可
以使用引导
(单引号或双引号)
来包围整个文字集合值。
以 INSERT 语句将集合 SET {7, 12,

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 237 -

59, 4} 插入到 tab_set 表的 set_col 列(图 1中定义):
EXEC SQL insert into tab_set values
(
5, 'set{7, 12, 59, 4}'
);
下图中的 UPDATE 语句重写前面 INSERT 添加到 tab_set 表的 SET 值。
图: 更改集合列
EXEC SQL update tab_set
set set_col = ("list{1,2,3,4}")
where id_col = 5;
重要: 如果省略 WHERE 子句,则 图 1 中的 UPDATE 语句将更改表 tab_set 中
的所有行的 set_col 列。
如果此文字集合值中出现任何字符值,
它与必须用引号括起来。
此条件创建嵌套引号。
例如,对于 SET(CHAR(5) 类型列 col1,文字值可以表示如下:
'SET{"abcde"}'
要在 GBase 8s ESQL/C 程序的 SQL 语句中指定嵌套的字符串,
则必须在引号中转义
每个双引号。以下 INSERT 语句形式如何对内双引号使用转义字符:
EXEC SQL insert into (col1) tab1
values ('SET{\"abcde\"}');
当将双引号字符串嵌套到另一个双引号中时,您不需要转义最内部的引号,如以下
INSERT 语句所示:
EXEC SQL insert into tabx
values (1, "set{""row(12345)""}");
如果集合或行类型是嵌套的,即,如果它包含另一个集合或行类型作为成员,内部集
合或行不需要用引号括起。例如,对于数据类型是 LIST(ROW(a INTEGER, b SMALLINT)
NOT NULL) 的列 col2,可以使用以下方式表达文字值:
'LIST{ROW(80, 3)}'
删除整个集合
要删除集合列中的整个集合,可以使用 UPDATE 语句将集合设置为空。
以下示例中的 UPDATE 语句有效地删除了 tab_set 表的 set_col 列中 id_col 等于
5 的行的整个集合。
EXEC SQL create table tab_set
(
id_col integer,
set_col set(integer not null)
);
EXEC SQL update tab_set set set_col = set{}
where id_col = 5;
以下示例显示了不带 WHERE 子句的同一 UPDATE 语句,将 tab_set 表所有行的
set_col 列设置为空。

GBase 8s ESQL/C 编程指南
南大通用数据技术股份有限公司
- 238 -

EXEC SQL update tab_set set set_col = set{};

该版本兼容GBase8cV5_S3.0.0B110 版本,可实现平滑升级。

算子buffer(session): 从gbase_heap_large 堆上分配。
算子buffer 均为session 级别,即如果设置gbase_buffer_result=1G,且任
务数为30,则在执行过程中,30 任务总共占用的gbase_buffer_result 就为1G x
30 = 30G,对于一般机器来说已经算很大了,这还不算其他的算子buffer。所以
如果在高并发环境中将某一个算子buffer 设置很大的话,很有可能就会出现内存
不足无法分配的情况。
gbase_buffer_distgrby
用于保存distinct 操作的中间结果;
gbase_buffer_hgrby
用于保存hash group by 操作的中间结果;
gbase_buffer_hj
用于保存hash join 操作的中间结果;
gbase_buffer_insert
用于保存insert values 的中间结果;
gbase_buffer_result
用于保存物化的中间结果;

GBase 8a MPP Cluster 最佳实践
4 参数调优
文档版本(2022-02-11)
南大通用数据技术股份有限公司
43
gbase_buffer_rowset
用于保存join 的行号;
gbase_buffer_sj
用于保存sort merge join 的中间结果,当join 条件是a>=b 或者a<=b 时,可
能会使用sort merge join;
gbase_buffer_sort
用于保存sort 操作的中间结果;
综述说明
算子buffer 的设置原则:
一般情况下(非高并发场景),根据系统内存大小,算子buffer 可以按照如下方
法设置:
gbase_buffer_hgrby 和gbase_buffer_hj 最大不超过4G;
gbase_buffer_result 最大不超过2G;
gbase_buffer_rowset 最大不超过1G;
其他算子使用系统估算即可。
如果在高并发场景下,
则不需要设置过大的算子buffer,
一般以系统自动评估为准。
但如果并发数过大,不排除需要人为将算子buffer 设置更小的情况。具体标准参
考上面提到的“算子buffer 的特点”,即并发数x 总算子buffer 大小不超过
gbase_heap_large 为宜,但最大也不能超过系统总内存大小。
修改算子buffer 的其它场景:
在进行poc 时,如果某条sql 由于某个算子执行过慢(瓶颈点可参考单机trace),
可以适当调大与之对应算子buffer。如根据trace 发现join 较慢,可以适当调大
gbase_buffer_hj 的值。
但是需要注意,
调整该值时必须不能影响其他sql 的执行,
且必须是现场允许修改系统参数时才可以。如整个测试只允许在开始时设置参数,
开始测试后就不允许再修改,如果开始时就把算子buffer 设置的很大,而后面又
有高并发测试,就很容易会出问题。

GBase 8a MPP Cluster 最佳实践
4 参数调优
文档版本(2022-02-11)
南大通用数据技术股份有限公司
44