

# SELECT 命令
<a name="s3-select-sql-reference-select"></a>

**重要**  
不再向新客户提供 Amazon S3 Select。Amazon S3 Select 的现有客户可以像往常一样继续使用该功能。[了解详情](https://www.amazonaws.cn/blogs/storage/how-to-optimize-querying-your-data-in-amazon-s3/) 

Amazon S3 Select 仅支持 `SELECT` SQL 命令。`SELECT` 支持以下 ANSI 标准子句：


+ `SELECT` list
+ `FROM` 子句 
+ `WHERE` 子句
+ `LIMIT` 子句

**注意**  
Amazon S3 Select 查询目前不支持子查询或联接。

## SELECT list
<a name="s3-select-sql-reference-select-list"></a>

`SELECT` 列表指定希望查询返回的列、函数和表达式。列表表示查询的输出。

```
SELECT *
SELECT {{projection1}} AS {{column_alias_1}}, {{projection2}} AS {{column_alias_2}}
```

第一个带 `*`（星号）的 `SELECT` 形式按原样返回每个传递 `WHERE` 子句的行。第二个 `SELECT` 格式使用用户定义的输出标量表达式 **`{{projection1}}`** 和 **`{{projection2}}`** 为每列创建一行。

## FROM 子句
<a name="s3-select-sql-reference-from"></a>

Amazon S3 Select 支持以下形式的 `FROM` 子句：

```
FROM {{table_name}}
FROM {{table_name alias}}
FROM {{table_name}} AS {{alias}}
```

在 `FROM` 子句的每种形式中，`table_name` 都是被查询的 `S3Object`。对于来自传统关系数据库的用户，可以将其视为一个数据库架构，其中包含一个表的多个视图。

按照标准 SQL，`FROM` 子句将会创建在 `WHERE` 子句中筛选并在 `SELECT` 列表中投影的行。

对于在 Amazon S3 Select 中存储的 JSON 对象，您也可以使用以下形式的 `FROM` 子句：

```
FROM S3Object[*].{{path}}
FROM S3Object[*].{{path alias}}
FROM S3Object[*].{{path}} AS {{alias}}
```

使用这种形式的 `FROM` 子句，您可以从 JSON 对象内的数组或对象中进行选择。您可以使用以下形式之一指定 `path`：
+ 通过名称（在对象中）：`.{{name}}` 或 `['{{name}}']`
+ 通过索引（在数组中）：`[{{index}}]`
+ 通过通配符（在对象中）：`.*`
+ 通过通配符（在数组中）：`[*]`

**注意**  
这种形式的 `FROM` 子句只适用于 JSON 对象。
通配符始终至少发出一条记录。如果没有匹配的记录，Amazon S3 Select 将发射值 `MISSING`。在输出序列化期间（在查询完成运行后），Amazon S3 Select 会将 `MISSING` 值替换为空记录。
聚合函数（`AVG`、`COUNT`、`MAX`、`MIN` 和 `SUM`）会跳过 `MISSING` 值。
如果您在使用通配符时未提供别名，则可使用路径中的最后一个元素引用行。例如，可以使用查询 `SELECT price FROM S3Object[*].books[*].price` 从书籍列表中选择所有价格。如果路径以通配符而不是名称结束，则可使用值 `_1` 来引用行。例如，您可以使用查询 `SELECT price FROM S3Object[*].books[*].price`，而不是 `SELECT _1.price FROM S3Object[*].books[*]`。
Amazon S3 Select 始终将 JSON 文档视为根级值组成的数组。因此，即使您查询的 JSON 对象只有一个根元素，`FROM` 子句也必须以 `S3Object[*]` 开头。但为了确保兼容性，Amazon S3 Select 允许您在不包含路径时省略通配符。因此，完整的子句 `FROM S3Object` 等效于 `FROM S3Object[*] as S3Object`。如果包含路径，则还必须使用通配符。因此，`FROM S3Object` 和 `FROM S3Object[*].{{path}}` 都是有效子句，但 `FROM S3Object.{{path}}` 不是。

**Example**  
**示例：**  
*示例 1*  
此示例显示使用以下数据集和查询时的结果：  

```
{ "Rules": [ {"id": "1"}, {"expr": "y > x"}, {"id": "2", "expr": "z = DEBUG"} ]}
{ "created": "June 27", "modified": "July 6" }
```

```
SELECT id FROM S3Object[*].Rules[*].id
```

```
{"id":"1"}
{}
{"id":"2"}
{}
```
Amazon S3 Select 因以下原因生成每个结果：  
+ `{"id":"id-1"}` – `S3Object[0].Rules[0].id` 产生了匹配。
+ `{}` – `S3Object[0].Rules[1].id` 与记录不匹配，因此 Amazon S3 Select 发出 `MISSING`，后者随后在输出序列化期间变为空记录并返回。
+ `{"id":"id-2"}` – `S3Object[0].Rules[2].id` 产生了匹配。
+ `{}` – `S3Object[1]` 对于 `Rules` 不匹配，因此 Amazon S3 Select 发出 `MISSING`，后者随后在输出序列化期间变为空记录并返回。
如果您不希望 Amazon S3 Select 在找不到匹配项时返回空记录，则可测试值 `MISSING`。以下查询将返回与上一查询相同的结果，但会省略空值：  

```
SELECT id FROM S3Object[*].Rules[*].id WHERE id IS NOT MISSING
```

```
{"id":"1"}
{"id":"2"}
```
*示例 2*  
此示例显示使用以下数据集和查询时的结果：  

```
{ "created": "936864000", "dir_name": "important_docs", "files": [ { "name": "." }, { "name": ".." }, { "name": ".aws" }, { "name": "downloads" } ], "owner": "Amazon S3" }
{ "created": "936864000", "dir_name": "other_docs", "files": [ { "name": "." }, { "name": ".." }, { "name": "my stuff" }, { "name": "backup" } ], "owner": "User" }
```

```
SELECT d.dir_name, d.files FROM S3Object[*] d
```

```
{"dir_name":"important_docs","files":[{"name":"."},{"name":".."},{"name":".aws"},{"name":"downloads"}]}
{"dir_name":"other_docs","files":[{"name":"."},{"name":".."},{"name":"my stuff"},{"name":"backup"}]}
```

```
SELECT _1.dir_name, _1.owner FROM S3Object[*]
```

```
{"dir_name":"important_docs","owner":"Amazon S3"}
{"dir_name":"other_docs","owner":"User"}
```

## WHERE 子句
<a name="s3-select-sql-reference-where"></a>

`WHERE` 子句遵循以下语法：

```
WHERE {{condition}}
```

`WHERE` 子句根据 `{{condition}}` 筛选行。condition 是具有布尔结果的表达式。只有 condition 计算结果为 `TRUE` 的行才会在结果中返回。

## LIMIT 子句
<a name="s3-select-sql-reference-limit"></a>

`LIMIT` 子句遵循以下语法：

```
LIMIT {{number}}
```

`LIMIT` 子句根据 `{{number}}` 限制您希望查询返回的记录数。

## 属性访问
<a name="s3-select-sql-reference-attribute-access"></a>

`SELECT` 和 `WHERE` 子句可以使用以下部分的任一方法引用记录数据，具体取决于将查询的文件是采用 CSV 还是 JSON 格式。

### CSV
<a name="s3-select-sql-reference-attribute-access-csv"></a>
+ **列编号** – 您可以引用列名为 `_{{N}}` 的行的第 *N* 列，其中 {{`N`}} 是列位置。位置计数从 1 开始。例如，第一列名为 `_1`，第二列名为 `_2`。

  您可以通过 `_{{N}}` 或 `{{alias}}._{{N}}` 引用列。例如，`_2` 和 `myAlias._2` 都是有效的，都可用于引用 `SELECT` 列表中的列和 `WHERE` 子句。
+ **Column Headers (列标头)** – 对于具有标头行的 CSV 格式的对象，可在 `SELECT` 列表和 `WHERE` 子句中使用这些标头。尤其在传统 SQL 的 `SELECT` 和 `WHERE` 子句表达式中，可以通过 `{{alias}}.{{column_name}}` 或 `{{column_name}}` 引用列。

### JSON
<a name="s3-select-sql-reference-attribute-access-json"></a>
+ **Document (文档)** – 可将 JSON 文档字段作为 `{{alias}}.{{name}}` 进行访问。还可以访问嵌套字段，例如 `{{alias}}.{{name1}}.{{name2}}.{{name3}}`。
+ **列表** – 可以将零基索引与 `[]` 运算符结合使用以访问 JSON 列表中的元素。例如，可以通过 `{{alias}}[1]` 访问列表中第二个元素。例如，您可以将访问列表元素与字段结合起来，例如 `{{alias}}.{{name1}}.{{name2}}[1].{{name3}}`。
+ **示例：**将此 JSON 对象视为示例数据集：

  ```
  {"name": "Susan Smith",
  "org": "engineering",
  "projects":
      [
       {"project_name":"project1", "completed":false},
       {"project_name":"project2", "completed":true}
      ]
  }
  ```

  *示例 1*

  以下查询返回以下结果：

  ```
  Select s.name from S3Object s
  ```

  ```
  {"name":"Susan Smith"}
  ```

  *示例 2*

  以下查询返回以下结果：

  ```
  Select s.projects[0].project_name from S3Object s
  ```

  ```
  {"project_name":"project1"}
  ```

## 标头和属性名称的区分大小写
<a name="s3-select-sql-reference-case-sensitivity"></a>

借助 Amazon S3 Select，您可以使用双引号指示区分大小写的列标头（对于 CSV 对象）和属性（对于 JSON 对象）。如果没有双引号，则对象标头和属性不区分大小写。如果出现歧义，则会抛出错误。

以下示例是：1) 带有指定列标头并对于查询请求将 `FileHeaderInfo` 设置为 `"Use"` 的 CSV 格式的 Amazon S3 对象；或 2) 带有指定属性的 JSON 格式的 Amazon S3 对象。

*示例 1：*所查询的对象具有标头或属性 `NAME`。
+ 以下表达式从对象成功返回值。因为没有引号，所以查询不区分大小写。

  ```
  SELECT s.name from S3Object s
  ```
+ 以下表达式导致出现 400 错误 `MissingHeaderName`。因为有引号，所以查询区分大小写。

  ```
  SELECT s."name" from S3Object s
  ```

*示例 2：*所查询的 Amazon S3 对象具有一个包含 `NAME` 的标头或属性和另一个包含 `name` 的标头或属性。
+ 以下表达式导致出现 400 错误 `AmbiguousFieldName`。由于无引号，所以查询不区分大小写，但有两个匹配项，因此引发错误。

  ```
  SELECT s.name from S3Object s
  ```
+ 以下表达式从对象成功返回值。因为有引号，所以查询区分大小写，因此没有歧义。

  ```
  SELECT s."NAME" from S3Object s
  ```

## 将保留关键字用作用户定义的术语
<a name="s3-select-sql-reference-using-keywords"></a>

Amazon S3 Select 具有一组保留关键字，在运行用于查询对象内容的 SQL 表达式时需要使用这组关键字。保留关键字包含函数名称、数据类型、运算符等。在某些情况下，诸如列标头（用于 CSV 文件）或属性（用于 JSON 对象）之类的用户定义的术语可能与保留关键字发生冲突。发生这种情况时，必须使用双引号指示您特意使用与保留关键字冲突的用户定义的术语。否则将会导致出现 400 解析错误。

有关保留关键字的完整列表，请参阅[保留关键字](s3-select-sql-reference-keyword-list.md)。

以下示例是：1) 带有指定列标头和对于查询请求将 `FileHeaderInfo` 设置为 `"Use"` 的 CSV 格式的 Amazon S3 对象；或 2) 带有指定属性的 JSON 格式的 Amazon S3 对象。

*示例：*所查询的对象具有名为 `CAST` 的标头和属性，但这是保留关键字。
+ 以下表达式从对象成功返回值。由于查询中使用了引号，因此 S3 Select 使用用户定义的标题或属性。

  ```
  SELECT s."CAST" from S3Object s
  ```
+ 以下表达式导致出现 400 解析错误。由于查询中不使用引号，因此 `CAST` 与保留关键字发生冲突。

  ```
  SELECT s.CAST from S3Object s
  ```

## 标量表达式
<a name="s3-select-sql-reference-scalar"></a>

在 `WHERE` 子句和 `SELECT` 列表中，您可以使用 SQL *标量表达式* (返回标量值的表达式)。它们具有以下形式：
+ **{{`literal`}}** 

  SQL 文本。
+ **{{`column_reference`}}** 

  对采用 `{{column_name}}` 或 `{{alias}}.{{column_name}}` 形式的列的引用。
+ **`{{unary_op}}`** **`{{expression}}`** 

  在这种情况下，***{{`unary_op`}}*** 是一个 SQL 一元运算符。
+ **`{{expression}}`** **`{{binary_op}}`** ***`{{expression}}`*** 

   在这种情况下，****`{{binary_op}}`**** 是一个 SQL 二进制运算符。
+ **`{{func_name}}`** 

   在这种情况下，**`{{func_name}}`** 是要调用的标量函数的名称。
+ ***`{{expression}}`*** `[ NOT ] BETWEEN` ***{{`expression`}}*** `AND` ***{{`expression`}}***
+ ***`{{expression}}`*** `LIKE` ***{{`expression`}}*** [ `ESCAPE` ***`{{expression}}`*** ]