
# 复合类型
复合类型表示行或记录的结构，它本质上就是字段名及其数据类型的列表。DWS允许支持将表的列声明为复合类型。复合类型本质上和表的行类型相同，但是如果只想定义一种类型，使用[CREATE TYPE](https://support.huaweicloud.com/sqlreference-dws/dws_06_0185.html)可避免创建一个实际的表。单独的复合类型也是很有用的，例如可以作为函数的参数或者返回类型。
#### 复合类型的声明
DWS支持用户使用[CREATE TYPE](https://support.huaweicloud.com/sqlreference-dws/dws_06_0185.html)定义复合类型：
```
CREATE TYPE complex AS (
        r       double precision,
        i       double precision
    );
CREATE TYPE inventory_item AS (
        name            text,
        supplier_id     integer,
        price           numeric
    );
```
定义复合类型之后，可用来创建表或函数：
```
CREATE TABLE on_hand (
        item      inventory_item,
        count     integer
    );
INSERT INTO on_hand VALUES (ROW('fuzzy dice', 42, 1.99), 1000);
```
```
CREATE FUNCTION price_extension(inventory_item, integer) RETURNS numeric
    AS 'SELECT $1.price * $2' LANGUAGE SQL;
SELECT price_extension(item, 10) FROM on_hand;
```
#### 构造复合值
要把复合值写作文字常量，可以将字段值括在圆括号中，并用逗号分隔。可以在任何字段值加上双引号，如果字段值包含逗号或括号则必须这样做。复合常量的一般格式如下：
```
'( val1 , val2 , ... )'
```
上文中的'("fuzzy dice",42,1.99)'便属于inventory_item类型的一个合法值。
要让一个字段为NULL，在列表中对应位置上空出即可。如果需要一个字段为空字符串，使用引号即可。例如下列示例，第一个字段是非NULL空字符串，第三个是NULL：
```
'("",42,)'
```
ROW表达式也能被用来构建组合值。例如：
```
ROW('fuzzy dice', 42, 1.99)
ROW('', 42, NULL)
```
#### 访问组合类型
要访问复合列的字段，可以写成一个点和字段的名称，就像从表名中选择字段一样。为了避免混淆，必须使用括号进行区分。例如，尝试从示例表on_hand中选择一些子域：
```
SELECT item.name FROM on_hand WHERE item.price > 9.99;
ERROR:  missing FROM-clause entry for table "item"
```
这样写是会与从表中选择字段混淆的，因为名称item会被当成是一个表名，而不是on_hand的一个列名。必须写成这样：
```
SELECT (item).name FROM on_hand WHERE (item).price > 9.99;
```
或者还需要使用表名（例如在一个多表查询中）：
```
SELECT (on_hand.item).name FROM on_hand WHERE (on_hand.item).price > 9.99;
```
现在加上括号的对象就被正确地解释为对item列的引用，然后可以从中选出子域。
只要从一个组合值中选择一个字段，相似的语法问题就适用。例如，要从返回组合值的函数的结果中选取一个字段，需要这样写：
```
SELECT (my_func(...)).field FROM ...
```
如果没有额外的圆括号，这将生成一个语法错误。
