AS SELECT 子句

使用 CREATE TABLE 语句的 AS SELECT 子句创建新的表并插入指定查询的结果集的数据行。

此语法在功能上与 SELECT 语句的 INTO STANDARD 和 INTO RAW 子句 非常相似。

当您使用 AS SELECT 子句创建新的查询结果表,并使用指定查询返回的限定行填充该表时,只有 CREATE TABLE 语句语法的以下的子集才有效:
元素 描述 限制 语法
column 查询的 FROM 子句中的表的列。这将是结果表中的列名。 必须在查询结果集中存在 标识符
column_alias 列的别名或显示标签。声明结果表中的列名称。 查询的 Projection 子句中的任何非平凡表达式在结果表中需要其列名的别名或显示标签 标识符
table 此处为结果表声明的名称 在数据库中表、同义词、视图和序列名称中必须是唯一的。 标识符
target_data_type 显式强制转型返回的数据类型。它将会是结果表中列的数据类型。 请参阅 对于目标数据类型的规则 数据类型

用法

当使用 CREATE TABLE . . . AS SELECT 语句创建新的永久表来存储查询的结果时,您可以指定该表的日志记录方式为 STANDARD 或 RAW 。如果您都忽略了这些关键字,则缺省为 STANDARD 。

您还可以可选地为此查询结果表指定下列属性:
  • 独立存储位置,或者分布存储方案e
  • 它的第一个 extent 和下一个 extent 的存储大小
  • 它的 PAGE 或 ROW 锁定粒度

如果您省略了存储或锁定规范,则数据库服务器使用缺省值。

如果在数据库服务器向该表填充大量 AS SELECT 子句中查询返回的行时发生了错误,则该操作会回滚,且不会创建或填充新表。

出现在 AS SELECT 子句的 Projection 列表中的列可以来自任何本地表、视图或来自远程数据库(必须在限定的表名中引用),但是新表必须在本地数据库中创建。

在 grid 环境中,如果 AS SELECT 子句的 FROM 子句中的表与所有参与的指定的 grid 或地区的数据库服务器具有相同的结构,则您可以包含 AS SELECT 子句以从grid 查询创建表。

结果表中列的名称

缺省情况下,新永久表中的列名称是在 Projection 子句的 SELECT 列表中指定的名称。如果星号(*)是 Projection 子句的 SELECT 列表,则星号将扩展为 SELECT 语句的 FROM 子句中对应的表或视图中的所有列名。由 FROM 子句指定表对象中的任何显式或隐式影子列不会由星号规范扩展。

在实现 Enterprise Replication 的系统上,可以使用 ALTER TABLE 语句的 ADD CRCOLS 、ADD REPLCHECK 和 ADD ERKEY 选项将相应的影子列添加到 AS SELECT 子句创建的结果表中。

除了简单列表达式之外, Projection 子句的 SELECT 列表中所有表达式都必须具有显示标签(也称为 列别名)。这用作新查询结果表中相应列的标识符。如果列表达式没有显示标签,则结果表使用查询的 FROM 子句中的源表中的列名。

在 CREATE TABLE . . . AS SELECT 语句中,可以使用以下两种方法指定列别名:
  • 作为逗号分隔的别名列表,紧跟在 TABLE 关键字后面,类似于 INSERT INTO . . . SELECT FROM 语句
  • 作为 Projection 子句中 SELECT 列表的一部分,与结构表中的 SELECT . . . INTO STANDARD 或 SELECT . . . INTO RAW 语句可以创建

如果在 CREATE TABLE . . . AS SELECT 语句中存在 Projection 子句的 SELECT 列表和 TABLE 关键字后面的逗号分隔的别名列表,则列别名的逗号分隔列表优先。在这种情况下,将忽略在 AS SELECT 子句中声明的任何列别名。

在以下情况中 CREATE TABLE . . . AS SELECT 语句会发生错误并失败:
  • I如果未为非重要列表达式声明显示标签或列别名。
  • 如果显示标签或列名称与新结果表中的另一列具有相同的名称。
  • 除了存储选项和 LOCK MODE 属性之外,CREATE TABLE . . . AS SELECT 语句不能为新表的列定义约束或任何其它特殊属性。
  • 如果逗号分隔的别名列表位于 TABLE 关键字之后,但该列表的别名数量少于 Projection 子句的 SELECT 列表中的表达式数量。
但是,如果 TABLE 关键字后面的列别名列表具有比 Projection 子句的 SELECT 列表更多的项目,在这种情况下,数据库服务器将忽略过多的列别名,并且不会发生异常。

支持的数据类型

CREATE TABLE . . . AS SELECT 已经支持用户定义的数据类型和所有内置的 GBase 8s 数据类型。

但是,在新的结果表中只允许有一个序列列。在包含了第一个 SERIAL 、SERIAL8 或 BIGSERIAL 类型的列后,所有随后的 SERIAL 、SERIAL8 或 BIGSERIAL 列作为 INTEGER 、INTEGER8 或 BIGINTEGER 列创建。

结果表上的限制

与大多数 DDL 语句一样,使用完全限定表名在其它数据库中创建新结果表的尝试会失败,并显示语法错误。类似地,创建于现有表具有相同名称的结果表是一个错误,除非 AS SELECT 子句包含 IF NOT EXISTS 关键字。 SELECT 语句的 SELECT INTO . . . TABLE 语法作为子查询的一部分时是无效的。

AS SELECT 子句可以包含在 ORDER BY 子句中而不在 Projection 子句的 SELECT 列表中的列。

IF NOT EXISTS 关键字

如果您在 AS SELECT 子句中为查询结果表声明的名称在数据库的永久表、同义词、视图和序列的名称中是唯一的,则无论 AS SELECT 子句是否包含 IF NOT EXISTS 关键字,数据库服务器总会创建查询结果表并填充所有查询返回的行。(如果查询没有返回行,则该结果表为空,但是它的结构已经在数据库的系统目录中注册,并作为一个新的永久表存在。)

如果 AS SELECT 子句包含了 IF NOT EXISTS 关键字,但您为结果表声明的名称在数据库的永久表的名称中并不是唯一的,则不会执行该 AS SELECT 子句定义的查询,并且数据库服务器返回以下消息:
0 row(s) retrieved into table.

如果 AS SELECT 子句忽略了 IF NOT EXISTS 关键字,且您为查询结果表声明的名称在数据库的永久表的名称中并不是唯一的,则不会创建结果表,并且数据库服务器返回一个错误。

创建和填充结果表的示例

以下示例创建了一个名为 rtabl 的新 RAW 表,用此表来存储连接查询的结果:

CREATE RAW TABLE IF NOT EXISTS rtab1
        AS
        SELECT t1col1, t1col2, t2col1 
        FROM tab1, tab2 
        WHERE t1col1 < 100 and t2col1 > 5;

在以上示例中,新的查询结果表 rtab1 将包含列 t1col1t1col2t2col1

下一个示例发生错误 -249 并失败,因为它没有为 col1+5 列表达式声明显示标签:

CREATE TABLE IF NOT EXISTS qtab1
        AS
        SELECT col1+5, col2
        FROM tab1;    

通过在包含 + 运算符的 Projection 子句中为列表表达式声明列别名 qcol1,以下修订的查询避免了之前示例返回的 -249 错误:

CREATE TABLE IF NOT EXISTS qtab1 (qcol1, col2)
        AS 
        SELECT col1+5, col2 
        FROM tab1;

以上正确的示例创建了标准表 qtabl 来存储 AS SELECT 子句的查询结果。

下一示例使用不同但等价的语句来在 AS SELECT 子句中声明相同的 qcol1 别名,而不是在列别名列表中声明:

CREATE TABLE IF NOT EXISTS qtab1
        AS
        SELECT col1+5 qcol1, col2 
        FROM tab1; 

以上的 CREATE TABLE 语句同样避免了 -249 错误,并创建结果和数据内容与前面示例中 qtabl 表相同的结果表。这这些示例中,结果表都有两列, qcol1col2 。如果 col1 是 INTEGER 类型,则 qcol1 将是 DECIMAL 类型,返回的数据类型来自 col1+5 表达式。

如语法图所示,CREATE TABLE 语句的 Storage 和 Lock Mode 选项对 AS SELECT 子句有效。以下示例使用 FRAGMENT BY EXPRESSION 关键字为查询结果表定义分布存储策略,其中 fcol1 列别名是分片键,ROW 是锁定粒度:

CREATE TABLE IF NOT EXISTS permtab (fcol1, col2)
        FRAGMENT BY EXPRESSION
        fcol1 < 300 IN dbs1,
        fcol1 >=300 IN dbs2
        LOCK MODE ROW
        AS SELECT col1::FLOAT, col2
        FROM tab1;  

任何 fcol1 值低于 300 的行会插入到 dbspace dbs1 中。具有较大 fcol1 值的行会存储在 dbs2 dbspace 中。

1 GBase 8s 扩展
2 请参阅 存储选项
3 请参阅 LOCK MODE 选项
4 请参阅 SELECT 语句