
# Select
#### 功能描述
SELECT语句用于从表中查询数据，是Spark SQL中最基本的查询语句。Spark 4.0支持完整的SELECT语法，包括LATERAL、PIVOT/UNPIVOT、OFFSET分页等特性。
#### 语法格式
```
[ WITH with_query [, ...] ]
SELECT [ ALL | DISTINCT ] { * | projectItem [, ...] }
  FROM table_reference [, ...]
  [ WHERE boolean_expression ]
  [ GROUP BY { expression | GROUPING SETS ( ... ) | ROLLUP ( ... ) | CUBE ( ... ) } [, ...] ]
  [ HAVING boolean_expression ]
  [ PIVOT ( aggregate_expr FOR pivot_column IN ( value1 [, ...] ) ) ]
  [ UNPIVOT ( value_column FOR name_column IN ( column1 [, ...] ) ) ]
  [ LATERAL VIEW function_expr AS alias [, ...] ]
  [ LATERAL ( subquery ) ]
 
  [ ORDER BY { expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] } [, ...] ]
  [ SORT BY { expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] } [, ...] ]
  [ CLUSTER BY expression [, ...] ]
  [ DISTRIBUTE BY expression [, ...] ]
  [ OFFSET integer_expression ]
  [ LIMIT integer_expression ]
```
其中 projectItem 为：
```
expression [ [ AS ] alias ]
```
table_reference 为：
```
{ table_name [ TABLE ] [ alias ]
  | join_table  | LATERAL ( subquery ) [ alias ]
  | ( subquery ) [ alias ]
  | VALUES ( { expression } [, ...] ) [, ...] [ alias ]
  | UNNEST(expression) [ alias ] }
```
#### 参数说明
表1参数说明 
| 参数                       | 说明                                                         |
|:---|:---|
| WITH with_query          | 定义公共表表达式（CTE），用于简化复杂查询，提高可读性。详见WITH...AS。                  |
| ALL                      | 返回所有行，包括重复行。为默认选项。                                         |
| DISTINCT                 | 从结果集中移除重复的行。                                               |
| \*                       | 查询所有列。                                                     |
| projectItem              | 指定查询的列或表达式，可使用AS指定别名。                                      |
| FROM table_reference     | 指定查询的数据源，可以是表名、子查询、JOIN结果、LATERAL子查询等。详见FROM。              |
| WHERE                    | 指定过滤条件，仅返回满足条件的行。详见WHERE。                                  |
| GROUP BY                 | 按指定表达式分组，通常与聚合函数配合使用。支持GROUPING SETS、ROLLUP、CUBE扩展。        |
| HAVING                   | 对GROUP BY的结果进行过滤。详见HAVING。                                 |
| PIVOT                    | 行转列操作，根据指定列的值将行数据旋转为列。                                     |
| UNPIVOT                  | 列转行操作，将列数据旋转为行。                                            |
| LATERAL VIEW             | 与表生成函数（如explode）配合使用，将函数输出展开为多行。                           |
| LATERAL (subquery)       | LATERAL子查询，允许子查询引用外部查询的列。                                  |
| ORDER BY                 | 全局排序。详见ORDER BY。                                           |
| SORT BY                  | 局部排序，每个Reducer内排序。详见SORT BY。                               |
| CLUSTER BY               | 分桶并桶内排序，等效于DISTRIBUTE BY + SORT BY同字段。详见CLUSTER BY。        |
| DISTRIBUTE BY            | 按指定字段分桶，将相同键值的数据分配到同一Reducer。详见DISTRIBUTE BY。              |
| OFFSET                   | 跳过前N行结果，用于分页查询。                                            |
| LIMIT                    | 限制返回的行数。                                                   |
| NULLS FIRST / NULLS LAST | 指定NULL值在排序结果中的位置。NULLS FIRST将NULL排在最前，NULLS LAST将NULL排在最后。 |
   
#### 注意事项
- 所查询的表必须是已经存在的表，否则提示查询错误。
- 在WHERE子句中使用NOT IN时，必须保证子查询结果集不包含任何NULL值。一旦存在NULL，整个查询结果将为空集。详见下方常见问题。
 
#### 示例
- 基本查询：
  ```
  SELECT * FROM student;
  ```
  
- 带DISTINCT去重：
  ```
  SELECT DISTINCT name FROM student;
  ```
  
- 带WHERE条件：
  ```
  SELECT name, score FROM student WHERE score > 90;
  ```
  
- 带GROUP BY和HAVING：
  ```
  SELECT class_id, AVG(score) AS avg_score FROM student
     GROUP BY class_id
     HAVING AVG(score) > 80;
  ```
  
- 带OFFSET分页（Spark 4.0）：
  ```
  SELECT * FROM student ORDER BY score DESC LIMIT 10 OFFSET 20;
  ```
  
- 带PIVOT行转列（Spark 4.0）：
  ```
  SELECT * FROM sales
     PIVOT (SUM(amount) FOR year IN (2023, 2024, 2025));
  ```
  
- 带LATERAL子查询（Spark 4.0）：
  ```
  SELECT * FROM orders, LATERAL (SELECT * FROM items WHERE items.order_id = orders.id);
  ```
  
 
#### :: 类型转换
```
SELECT '123' :: INT;
 -- 等价于 CAST('123' AS INT)
```
#### COLLATE 排序规则
```
SELECT name FROM t ORDER BY name COLLATE unicode_ci;
```
#### 常见问题：NOT IN子查询中有NULL值，查询结果为空怎么办？
- **问题概述**：SQL语法中只要NOT IN子查询中有一个NULL值，整个查询结果就会是空集（无数据返回）。
- **示例** ：如下示例中期望的结果是3，但是反馈的是空集。
  ```
  -- 表A        -- 表B
  id            value
  ---           -----
  1             1
  2             2
  3
  ```
  执行以下SQL语句：
  ```
  SELECT * FROM A
  WHERE id NOT IN (SELECT value FROM B);
  ```
  
- **原因分析** ：
  ```
  id NOT IN (1, 2, NULL) 等价于 id <> 1 AND id <> 2 AND id <> NULL
  ```
  id \<\> NULL 的结果是UNKNOWN（SQL的三值逻辑），整个表达式为FALSE，因此无数据返回。
  
- **解决方案** ：
  方案1：用NOT EXISTS替代NOT IN
  ```
  SELECT * FROM A
  WHERE NOT EXISTS (
    SELECT 1 FROM B WHERE B.value = A.id
  );
  ```
  方案2：在子查询中过滤掉NULL
  ```
  SELECT * FROM A
  WHERE id NOT IN (
    SELECT value FROM B WHERE value IS NOT NULL
  );
  ```
  
 
