#
第二十章 SQL命令 CREATE TABLE AS SELECT 将现有表中的列定义和列数据复制到新表中。 # 大纲 ```sqk CREATE TABLE table-name AS query [shard-key] [WITH table-option] ``` # 参数 - `table-name` 要创建的表的名称,指定为有效标识符。表名可以是限定的(`schema.table`),也可以是非限定的(`Table`)。未限定的表名采用缺省模式名。 - `query` 为新表提供列定义和列数据的`SELECT`查询。此查询可以指定表、视图或多个联接的表。 - `shard-key` - 可选-切片键定义,由切片键本身或后跟附加切片键定义语法组成。 - `WITH table-option` - 可选-一个或多个表选项的逗号分隔列表,如`%CLASSPARAMETER`关键字后跟名称和关联的文字,或`STORAGETYPE=ROW`或`STORAGETYPE=COLUMN`。 # 描述 `CREATE TABLE AS SELECT`命令通过复制`SELECT`查询中指定的现有表(或多个表)中的列定义和列数据来创建新表。`SELECT`查询可以指定表或视图的任意组合。 注:`CREATE TABLE AS SELECT COPPLICES FROM`现有表定义。使用`CREATE TABLE`命令指定新的表定义。 还可以使用`QueryToTable()`方法调用复制表操作: ```java DO $SYSTEM.SQL.Schema.QueryToTable(query,table-name,0) ``` # 复制数据定义 - `CREATE TABLE AS SELECT`从查询表复制列定义。要重命名复制的列,请在查询中指定列别名。 如果查询指定联接的表,`CREATE TABLE AS SELECT`可以从多个表复制列定义。 - `CREATE TABLE AS SELECT`始终将`RowID`定义为隐藏。 - 如果源表具有隐藏的`RowID`,则`CREATE TABLE AS SELECT`不会复制源表`RowID`,但会为创建的表创建新的`RowID`列。复制的行将被分配新的连续`RowID`值。 - 如果源表具有公共(非隐藏)`RowID`,或者如果查询显式选择了隐藏的`RowID`,则`CREATE TABLE AS SELECT`将为该表创建一个新的`RowID`列。源表`RowID`作为普通的`BigInt`字段复制到新表中,该字段不是隐藏的、不是唯一的,也不是必需的。如果源表`RowID`命名为`“ID”`,则新表的`RowID`命名为`“ID1”`。 - 如果源表有标识字段,`CREATE TABLE AS SELECT`会将其及其当前数据复制为非零正整数的普通`BIGINT`字段,该字段既不唯一也不是必需的。 - `CREATE TABLE AS SELECT`定义`IDKEY`索引。它不复制与复制的列定义相关联的索引。 - `CREATE TABLE AS SELECT`不复制任何列约束:它不复制与复制的列定义关联的`NULL/NOT NULL`、`UNIQUE`、`PRIMARY KEY`或`FOREIGN KEY`约束。 - `CREATE TABLE AS SELECT`不复制与复制的列定义关联的默认限制或值。 - `CREATE TABLE AS SELECT`不复制与复制的列定义关联的`COMPUTECODE`数据约束。 - `CREATE TABLE AS SELECT`不复制与复制表或列定义关联的`%DESCRIPTION`字符串。 # 权限 `CREATE TABLE AS SELECT`命令是一个特权操作。用户必须具有`%CREATE_TABLE`管理权限才能执行`CREATE TABLE AS SELECT`。否则将导致`%msg`用户`‘name’`没有`%CREATE_TABLE`权限的`SQLCODE-99`错误。如果拥有适当的授予权限,则可以使用`GRANT`命令将`%CREATE_TABLE`权限分配给用户或角色。管理权限是特定于命名空间的。 用户必须对`query`中指定的表具有`SELECT`权限。 ## 表名 表名可以是限定的,也可以是非限定的。 - 非限定表名具有以下语法:`tablename`;它省略架构(和句点(`.`)。字符)。未限定的表名采用缺省模式名。系统范围内的初始默认架构名称是`SQLUser`,它对应于默认的类包名称`User`。架构搜索路径值将被忽略。 可以配置默认架构名称。 要确定当前系统范围内的默认架构名称,请使用`$SYSTEM.SQL.Schema.Default()`方法。 - 限定表名具有以下语法:`schema.tablename`。它可以指定现有的架构名称,也可以指定新的架构名称。指定现有架构名称会将该表放入该架构中。指定新的模式名称将创建该模式(以及关联的类包),并将表放入该模式中。 表名和模式名遵循SQL标识符命名约定,受使用非字母数字字符、唯一性和最大长度的附加约束。以%字符开头的名称保留供系统使用。默认情况下,模式名和表名是简单标识符,不区分大小写。 IRIS使用表名生成相应的类名。 IRIS使用架构名称来生成相应的类包名称。类名仅包含字母数字字符(字母和数字),并且在前`96`个字符内必须是唯一的。要生成类名 IRIS首先从表名中剔除符号(非字母数字)字符,然后生成唯一的类名,从而施加唯一性和最大长度限制。要生成包名,它然后对架构名中的符号(非字母数字)字符进行剥离或执行特殊处理。然后, IRIS生成唯一的包名,施加唯一性和最大长度限制。 可以对架构和表使用相同的名称。同一架构中的表和视图不能使用相同的名称。 架构名称不区分大小写;相应的类包名称区分大小写。如果指定的架构名称仅与现有类包名的大小写不同,并且包定义为空(不包含类定义)。 IRIS通过更改类包名称的大小写来协调这两个名称。 IRIS支持`16`位(宽)字符作为表名和列名。对于大多数区域设置,可以使用重音字母作为表名,并且重音符号包含在生成的类名中。以下示例对SQL表名执行验证测试: ```java ClassMethod CreateTableAsSelect(tname) { s x = $SYSTEM.SQL.IsValidRegularIdentifier(tname) if x = 0 { IF $l(tname)>200 { w "表名太长" QUIT } elseif $SYSTEM.SQL.IsReservedWord(tname) { w "表名是保留字" q } else { w "表名包含无效字符",! s nls = ##class(%SYS.NLS.Locale).%New() if nls.Language [ "Japanese" { w "日语区域设置不能使用重音字母" q } q } } else { w tname," 是有效的表名" } } ``` 注意:日语区域设置不支持标识符中的重音字母字符。日语标识符可以包含(除日语字符外)拉丁字母字符`A-Z`和`a-z`(`65-90`和`97-122`)、下划线字符(`95`)和希腊大写字母字符(`913-929`和`931-937`)。`Nls.language`测试使用[(`CONTAINS`运算符)而不是=,因为不同的操作系统平台有不同的日语区域设置。 # 表存在 要确定当前命名空间中是否已存在表,请使用`$SYSTEM.SQL.Schema.TableExists(“schema.tname”)`. 默认情况下,当创建与现有表同名的表时, IRIS拒绝`REATE TABLE`尝试并发出`SQLCODE-201`错误。要确定当前系统范围的配置设置,请调用`$SYSTEM.SQL.CurrentSettings()`,它将显示`Allow DDL CREATE TABLE`或`CREATE VIEW for Existing table`或`view`设置。默认值为`0`;这是此选项的推荐设置。如果此选项设置为`1` IRIS将删除与该表关联的类定义,然后重新创建它。这与执行`DROP TABLE`、删除现有表,然后执行`CREATE TABLE`大致相同。在这种情况下,强烈建议`$SYSTEM.SQL.CurrentSettings()`,Does DDL DROP TABLE delete the table's data?值设置为1(默认值)。 在管理门户、系统管理、配置、SQL和对象设置中,通过选中忽略冗余DDL语句复选框,可以在系统范围内设置此选项(以及其他类似的创建、更改和删除选项)。 # WITH table-option 可以在`SELECT`查询之后指定可选的`WITH`子句。`WITH`子句可以包含逗号分隔的`%CLASSPARAMETER`子句列表和/或`STORAGETYPE`子句。 使用`%CLASSPARAMETER`关键字可以将类参数定义为`CREATE TABLE AS SELECT`命令的一部分。类参数始终定义为常量值。关键字`%CLASSPARAMETER`后跟类参数名称、可选等号和要分配给该类参数的文字值(字符串或数字)。 可以指定多个`%CLASSPARAMETER`关键字子句,每个子句定义一个类参数。多个`%CLASSPARAMETER`子句用逗号分隔。 例如,默认情况下,`CREATE TABLE AS SELECT`将使用生成的全局名称(如`^EPgS.D8T6.1`)为创建的表创建`IDKEY`索引;其他索引使用具有唯一整数后缀的相同全局名称。以下示例显示如何为`IDKEY`索引和未来的其他索引指定显式全局名称: ```sql CREATE TABLE Sample.YoungPeople AS SELECT Name,Age FROM Sample.People WHERE Age<21 WITH %CLASSPARAMETER DEFAULTGLOBAL = '^GL.UNDERTWENTYONE' ```