ANSI合规性

在Spark SQL中,有两个选项符合SQL标准: spark.sql.ansi.enabled spark.sql.storeAssignmentPolicy (见下表以获取详细信息)。

spark.sql.ansi.enabled 设置为 true 时,Spark SQL 使用 ANSI 兼容的方言,而不是 Hive 兼容的。 例如,如果 SQL 操作符/函数的输入无效,Spark 将在运行时抛出异常,而不是返回 null 结果。 一些 ANSI 方言特性可能并不是直接来自 ANSI SQL 标准,但它们的行为与 ANSI SQL 的风格一致。

此外,Spark SQL 有一个独立的选项来控制在向表中插入行时的隐式类型转换行为。
类型转换行为在标准中被定义为存储分配规则。

spark.sql.storeAssignmentPolicy 被设置为 ANSI 时,Spark SQL 遵循 ANSI 存储分配规则。这是一个单独的配置,因为它的默认值是 ANSI ,而配置 spark.sql.ansi.enabled 默认是禁用的。

属性名称 默认值 含义 自版本
spark.sql.ansi.enabled false 当为真时,Spark 尝试遵循 ANSI SQL 规范:
1. Spark SQL 将针对无效操作抛出运行时异常,包括整数溢出错误、字符串解析错误等。
2. Spark 将使用不同的类型强制转换规则来解决数据类型之间的冲突。这些规则始终基于数据类型优先级。
3.0.0
spark.sql.storeAssignmentPolicy ANSI 当向不同数据类型的列插入值时,Spark 将执行类型转换。目前,我们支持 3 种类型强制转换规则:ANSI、legacy 和 strict。
1. 使用 ANSI 政策时,Spark 按照 ANSI SQL 执行类型强制转换。在实践中,行为大致与 PostgreSQL 相同。它不允许某些不合理的类型转换,例如将字符串转换为整数或将双精度转换为布尔值。在向数值类型列插入时,如果值超出目标数据类型的范围,将抛出溢出错误。
2. 使用 legacy 政策时,只要是有效的转换,Spark 允许类型强制转换,这非常宽松。例如,将字符串转换为整数或将双精度转换为布尔值是允许的。这也是 Spark 2.x 中唯一的行为,并且与 Hive 兼容。
3. 使用 strict 政策时,Spark 不允许在类型强制转换中出现任何可能的精度损失或数据截断,例如不允许将双精度转换为整数或将十进制转换为双精度。
3.0.0

以下小节介绍了在启用ANSI模式时,算术运算、类型转换和SQL解析中的行为变化。对于Spark SQL中的类型转换,它们分为三种类型,本文将逐一介绍:转换、存储赋值和类型强制转换。

算术运算

在Spark SQL中,对数值类型(小数类型除外)进行的算术操作默认不检查溢出。 这意味着如果某个操作导致溢出,结果与Java/Scala程序中相应操作的结果相同(例如,如果两个整数的和超过可表示的最大值,结果是一个负数)。 另一方面,Spark SQL对小数溢出的返回值是null。 当 spark.sql.ansi.enabled 设置为 true 并且在数值和区间算术操作中发生溢出时,它会在运行时抛出算术异常。

-- `spark.sql.ansi.enabled=true`
SELECT 2147483647 + 1;
org.apache.spark.SparkArithmeticException: [ARITHMETIC_OVERFLOW] integer 溢出. 使用 'try_add'  容忍 溢出 并且 返回 NULL 代替. 如果 需要 设置 spark.sql.ansi.enabled  "false"  绕过  错误.
== SQL(line 1, position 8) ==
SELECT 2147483647 + 1
^^^^^^^^^^^^^^
SELECT abs(-2147483648);
org.apache.spark.SparkArithmeticException: [ARITHMETIC_OVERFLOW] integer 溢出. 如果 需要 设置 spark.sql.ansi.enabled  "false"  绕过  错误.
-- `spark.sql.ansi.enabled=false`
SELECT 2147483647 + 1;
+----------------+
|(2147483647 + 1)|
+----------------+
| -2147483648|
+----------------+
SELECT abs(-2147483648);
+----------------+
|abs(-2147483648)|
+----------------+
| -2147483648|
+----------------+

演员表

spark.sql.ansi.enabled 设置为 true 时,通过 CAST 语法进行的显式转换会对标准中定义的非法转换模式抛出运行时异常,例如从字符串转换为整数。

此外,ANSI SQL模式不允许在关闭ANSI模式时允许的以下类型转换:

CAST 表达式中,源数据类型和目标数据类型的有效组合如下表所示。“Y”表示该组合在语法上是有效的,没有限制,而“N”表示该组合是无效的。

来源\目标 数字 字符串 日期 时间戳 无时区时间戳 时间间隔 布尔值 二进制 数组 映射 结构
数字
字符串
日期
时间戳
无时区时间戳
时间间隔
布尔值
二进制
数组
映射
结构

在上表中,所有带有新语法的 CAST 都标记为红色 Y :

-- 显式转换的示例
-- `spark.sql.ansi.enabled=true`
SELECT CAST('a' AS INT);
org.apache.spark.SparkNumberFormatException: [CAST_INVALID_INPUT]  'a'  类型 "STRING" 不能  转换  "INT" 因为   格式不正确. 请修正  根据 语法, 或者 更改  目标 类型. 使用 `try_cast`  容忍 格式不正确  输入  返回 NULL 作为. 如果 必要 则设置 "spark.sql.ansi.enabled"  "false"  绕过  错误.
== SQL( 1, 位置 8) ==
SELECT CAST('a' AS INT)
^^^^^^^^^^^^^^^^
SELECT CAST(2147483648L AS INT);
org.apache.spark.SparkArithmeticException: [CAST_OVERFLOW]  2147483648L  类型 "BIGINT" 不能  转换  "INT" 因为 溢出. 使用 `try_cast`  容忍 溢出  返回 NULL 作为. 如果 必要 则设置 "spark.sql.ansi.enabled"  "false"  绕过  错误.
SELECT CAST(DATE'2020-01-01' AS INT);
org.apache.spark.sql.AnalysisException: 无法 解析 'CAST(DATE '2020-01-01' AS INT)' 由于 数据 类型 不匹配: 无法 转换 date  int.
    date 转换为 int,  可以 使用 函数 UNIX_DATE 作为.
-- `spark.sql.ansi.enabled=false` (这是默认行为)
SELECT CAST('a' AS INT);
+--------------+
|CAST(a AS INT)|
+--------------+
| null|
+--------------+
SELECT CAST(2147483648L AS INT);
+-----------------------+
|CAST(2147483648 AS INT)|
+-----------------------+
| -2147483648|
+-----------------------+
SELECT CAST(DATE'2020-01-01' AS INT)
+------------------------------+
|CAST(DATE '2020-01-01' AS INT)|
+------------------------------+
| null|
+------------------------------+
-- 存储赋值规则的示例
CREATE TABLE t (v INT);
-- `spark.sql.storeAssignmentPolicy=ANSI`
INSERT INTO t VALUES ('1');
org.apache.spark.sql.AnalysisException: [INCOMPATIBLE_DATA_FOR_TABLE.CANNOT_SAFELY_CAST] 无法 写入 不兼容的 数据   `spark_catalog`.`default`.`t`: 无法安全地 转换 `v`: "STRING"  "INT".
-- `spark.sql.storeAssignmentPolicy=LEGACY` (这是直到Spark 2.x的遗留行为)
INSERT INTO t VALUES ('1');
SELECT * FROM t;
+---+
| v|
+---+
| 1|
+---+

取整在铸造中

当将带有小数的十进制数转换为以SECOND作为结束单位的时间间隔类型(如INTERVAL HOUR TO SECOND)时,Spark将小数部分四舍五入到“最近的邻居”,除非两个邻居距离相等,在这种情况下向上舍入。

店铺分配

如开头所述,当 spark.sql.storeAssignmentPolicy 被设置为 ANSI (这是默认值)时,Spark SQL 遵循 ANSI 存储分配规则进行表插入。表插入中源数据类型和目标数据类型的有效组合在下表中给出。

来源\目标 数字 字符串 日期 时间戳 时间戳_NTZ 区间 布尔值 二进制 数组 映射 结构
数字 Y Y N N N N N N N N N
字符串 N Y N N N N N N N N N
日期 N Y Y Y Y N N N N N N
时间戳 N Y Y Y Y N N N N N N
时间戳_NTZ N Y Y Y Y N N N N N N
区间 N Y N N N N* N N N N N
布尔值 N Y N N N N Y N N N N
二进制 N Y N N N N N Y N N N
数组 N N N N N N N N Y** N N
映射 N N N N N N N N N Y** N
结构 N N N N N N N N N N Y**

* Spark不支持间隔类型的表列。

** 对于数组/映射/结构类型,数据类型检查规则递归适用于其组成元素。

在插入表时,Spark会因数值溢出而抛出异常。

CREATE TABLE test(i INT);
INSERT INTO test VALUES (2147483648L);
org.apache.spark.SparkArithmeticException: [CAST_OVERFLOW_IN_TABLE_INSERT] 失败 插入 一个  类型为 "BIGINT"   "INT" 类型  `i` 由于 溢出. 使用 `try_cast` 处理 输入    容忍 溢出 并且 返回 NULL 作为.

类型转换

类型提升与优先级

spark.sql.ansi.enabled 设置为 true 时,Spark SQL 使用几条规则来处理数据类型之间的冲突。解决冲突的核心是类型优先级列表,该列表定义给定数据类型的值是否可以隐式提高到另一种数据类型。

数据类型 优先级列表(从最狭窄到最宽)
字节 Byte -> Short -> Int -> Long -> Decimal -> Float* -> Double
短整型 Short -> Int -> Long -> Decimal-> Float* -> Double
整型 Int -> Long -> Decimal -> Float* -> Double
长整型 Long -> Decimal -> Float* -> Double
十进制 Decimal -> Float* -> Double
浮点型 Float -> Double
双精度 Double
日期 Date -> Timestamp_NTZ -> Timestamp
时间戳 Timestamp
字符串 String, Long -> Double, Date -> Timestamp_NTZ -> Timestamp , Boolean, Binary **
二进制 Binary
布尔型 Boolean
区间 Interval
映射 Map***
数组 Array***
结构 Struct***

* 为了避免精度损失,最小公共类型解析中跳过浮点数。

** 字符串可以提升为多种数据类型。请注意,Byte/Short/Int/Decimal/Float不在此优先级列表中。Byte/Short/Int和字符串之间的最少共同类型是Long,而Decimal/Float之间的最少共同类型是Double。

*** 对于复杂类型,优先级规则递归适用于其组成元素。

未类型化的NULL适用特殊规则。NULL可以提升为任何其他类型。

这是优先级列表作为有向树的图形表示:

类型优先级列表

最小公共类型解析

一组类型中最不常见的类型是从优先级列表中通过该组类型的所有元素可到达的最狭窄类型。

最小公共类型解析用于:

-- coalesce 函数接受任何类型的参数,只要它们具有最小公有类型。
-- 结果类型是参数的最小公有类型。
> SET spark.sql.ansi.enabled=true;
> SELECT typeof(coalesce(1Y, 1L, NULL));
BIGINT
> SELECT typeof(coalesce(1, DATE'2020-01-01'));
错误: 不兼容 类型 [INT, DATE]
> SELECT typeof(coalesce(ARRAY(1Y), ARRAY(1L)));
ARRAY<BIGINT>
> SELECT typeof(coalesce(1, 1F));
DOUBLE
> SELECT typeof(coalesce(1L, 1F));
DOUBLE
> SELECT (typeof(coalesce(1BD, 1F)));
DOUBLE
> SELECT typeof(coalesce(1, '2147483648'))
BIGINT
> SELECT typeof(coalesce(1.0, '2147483648'))
DOUBLE
> SELECT typeof(coalesce(DATE'2021-01-01', '2022-01-01'))
DATE

SQL 函数

函数调用

在ANSI模式下(spark.sql.ansi.enabled=true),Spark SQL的函数调用:

> SET spark.sql.ansi.enabled=true;
-- 隐式将 Int 转换为字符串类型
> SELECT concat('total number: ', 1);
total number: 1
-- 隐式将时间戳转换为日期类型
> select datediff(now(), current_date);
0
-- 隐式将字符串转换为双精度类型
> SELECT ceil('0.1');
1
-- 特殊规则:隐式将 NULL 转换为日期类型
> SELECT year(null);
NULL
> CREATE TABLE t(s string);
-- 不能将字符串列存储为数字类型。
> SELECT ceil(s) from t;
Error in query: cannot resolve 'CEIL(spark_catalog.default.t.s)' due to data type mismatch
-- 不能将字符串列存储为日期类型。
> select year(s) from t;
Error in query: cannot resolve 'year(spark_catalog.default.t.s)' due to data type mismatch

具有不同行为的函数

某些SQL函数的行为在ANSI模式下可能会有所不同 ( spark.sql.ansi.enabled=true ).

SQL 操作符

某些SQL运算符的行为在ANSI模式下可能有所不同 ( spark.sql.ansi.enabled=true ).

ANSI模式下的有用函数

当ANSI模式开启时,它会对无效操作抛出异常。您可以使用以下SQL函数来抑制这些异常。

SQL关键字(可选,默认禁用)

spark.sql.ansi.enabled spark.sql.ansi.enforceReservedKeywords 都为真时,Spark SQL 将使用 ANSI 模式解析器。

使用ANSI模式解析器,Spark SQL有两种关键字:

使用默认解析器,Spark SQL 有两种关键字:

默认情况下, spark.sql.ansi.enabled spark.sql.ansi.enforceReservedKeywords 都是 false。

以下是Spark SQL中所有关键字的列表。

td>非保留
关键字 Spark SQL
ANSI 模式
Spark SQL
默认模式
SQL-2016
ADD 非保留 非保留 非保留
AFTER 非保留 非保留 非保留
ALL 保留 非保留 保留
ALTER 非保留 非保留 保留
ALWAYS 非保留 非保留 非保留
ANALYZE 非保留 非保留 非保留
AND 保留 非保留 保留
ANTI 非保留 严格非保留 非保留
ANY 保留 非保留 保留
ANY_VALUE 非保留 非保留 非保留
ARCHIVE 非保留 非保留 非保留
ARRAY 非保留 非保留 保留
AS 保留 非保留 保留
ASC 非保留 非保留 非保留
AT 非保留 非保留 保留
AUTHORIZATION 保留 非保留 保留
BETWEEN 非保留 非保留 保留
BIGINT 非保留 非保留 保留
BINARY 非保留 非保留 保留
BOOLEAN 非保留 非保留 保留
BOTH 保留 非保留 保留
BUCKET 非保留 非保留 非保留
BUCKETS 非保留 非保留 非保留
BY 非保留 非保留 保留
BYTE 非保留 非保留 非保留
CACHE 非保留 非保留 非保留
CASCADE 非保留 非保留 非保留
CASE 保留 非保留 保留
CAST 保留 非保留 保留
CATALOG 非保留 非保留 非保留
CATALOGS 非保留 非保留 非保留
CHANGE 非保留 非保留 非保留
CHAR 非保留 非保留 保留
CHARACTER 非保留 非保留 保留
CHECK 保留 非保留 保留
CLEAR 非保留 非保留 非保留
CLUSTER 非保留 非保留 非保留
CLUSTERED 非保留 非保留 非保留
CODEGEN 非保留 非保留 非保留
COLLATE 保留 非保留 保留
COLLECTION 非保留 非保留 非保留
COLUMN 保留 非保留 保留
COLUMNS 非保留 非保留 非保留
COMMENT 非保留 非保留 非保留
COMMIT 非保留 非保留 保留
COMPACT 非保留 非保留 非保留
COMPACTIONS 非保留 非保留 非保留
COMPUTE 非保留 非保留 非保留
CONCATENATE 非保留 非保留 非保留
CONSTRAINT 保留 非保留 保留
COST 非保留 非保留 非保留
CREATE 保留 非保留 保留
CROSS 保留 严格非保留 保留
CUBE 非保留 非保留 保留
CURRENT 非保留 非保留 保留
CURRENT_DATE 保留 非保留 保留
CURRENT_TIME 保留 非保留 保留
CURRENT_TIMESTAMP 保留 非保留 保留
CURRENT_USER 保留 非保留 保留
DATA 非保留 非保留 非保留
DATE 非保留 非保留 保留
DATABASE 非保留 非保留 非保留
DATABASES 非保留 非保留 非保留
DATEADD 非保留 非保留 非保留
DATE_ADD 非保留 非保留 非保留
DATEDIFF 非保留 非保留 非保留
DATE_DIFF 非保留 非保留 非保留
DAY 非保留 非保留 非保留
DAYS 非保留 非保留 非保留
DAYOFYEAR 非保留 非保留 非保留
DBPROPERTIES 非保留 非保留 非保留
DEC 非保留 非保留 保留
DECIMAL 非保留 非保留 保留
DEFAULT 非保留 非保留 非保留
DEFINED 非保留 非保留 非保留
DELETE 非保留 非保留 保留
DELIMITED 非保留 非保留 非保留
DESC 非保留 非保留 非保留
DESCRIBE 非保留 非保留 保留
DFS 非保留 非保留 非保留
DIRECTORIES 非保留 非保留 非保留
DIRECTORY 非保留 非保留 非保留
DISTINCT 保留 非保留 保留
DISTRIBUTE 非保留 非保留 非保留
DIV 非保留 非保留 不是关键字
DOUBLE 非保留 非保留 保留
DROP 非保留 非保留 保留
ELSE 保留 非保留 保留
END 保留 非保留 保留
ESCAPE 保留 非保留 保留
ESCAPED 非保留 非保留 非保留
EXCEPT 保留 严格非保留 保留
EXCHANGE 非保留 非保留 非保留
EXCLUDE 非保留 非保留 非保留
EXISTS 非保留 非保留 保留
EXPLAIN 非保留 非保留 非保留
EXPORT 非保留 非保留 非保留
EXTENDED 非保留 非保留 非保留
EXTERNAL 非保留 非保留 保留
EXTRACT 非保留 非保留 保留
FALSE 保留 非保留 保留
FETCH 保留 非保留 保留
FIELDS 非保留 非保留 非保留
FILTER 保留 非保留 保留
FILEFORMAT 非保留 非保留 非保留
FIRST 非保留 非保留 非保留
FLOAT 非保留 非保留 保留
FOLLOWING 非保留 非保留 非保留
FOR 保留 非保留 保留
FOREIGN 保留 非保留 保留
FORMAT 非保留 非保留 非保留
FORMATTED 非保留 非保留 非保留
FROM 保留 非保留 保留
FULL 保留 严格非保留 保留
FUNCTION 非保留 非保留 保留
FUNCTIONS 非保留 非保留 非保留
GENERATED 非保留 非保留 非保留
GLOBAL 非保留 非保留 保留
GRANT 保留 非保留 保留
GROUP 保留 非保留 保留
GROUPING 非保留 非保留 保留
HAVING 保留 非保留 保留
HOUR 非保留 非保留 非保留
HOURS 非保留 非保留 非保留
IDENTIFIER 非保留 非保留 非保留
IF 非保留 非保留 不是关键字
IGNORE 非保留 非保留 非保留
IMPORT 非保留 非保留 非保留
IN 保留 非保留 保留
INCLUDE 非保留 非保留 非保留
INDEX 非保留 非保留 非保留
INDEXES 非保留 非保留 非保留
INNER 保留 严格非保留 保留
INPATH 非保留 非保留 非保留
INPUTFORMAT 非保留 非保留 非保留
INSERT 非保留 非保留 保留
INT 非保留 非保留 保留
INTEGER 非保留 非保留 保留
INTERSECT 保留 严格非保留 保留
INTERVAL 非保留 非保留 保留
INTO 保留 非保留 保留
IS 保留 非保留 保留
ITEMS 非保留 非保留 非保留
JOIN 保留 严格非保留 保留
KEYS 非保留 非保留 非保留
LAST 非保留 非保留 非保留
LATERAL 保留 严格非保留 保留
LAZY 非保留 非保留 非保留
LEADING 保留 非保留 保留
LEFT 保留 严格非保留 保留
LIKE 非保留 非保留 保留
ILIKE 非保留 非保留 非保留
LIMIT 非保留 非保留 非保留
LINES 非保留 非保留 非保留
LIST 非保留 非保留 非保留
LOAD 非保留 非保留 非保留
LOCAL 非保留 非保留 保留
LOCATION 非保留 非保留 非保留
LOCK 非保留 非保留 非保留
LOCKS 非保留 非保留 非保留
LOGICAL 非保留 非保留 非保留
LONG 非保留 非保留 非保留
MACRO 非保留 非保留 非保留
MAP 非保留 非保留 非保留
MATCHED 非保留 非保留 非保留
MERGE 非保留 非保留 非保留
MICROSECOND 非保留 非保留 非保留
MICROSECONDS 非保留 非保留 非保留
MILLISECOND 非保留 非保留 非保留
MILLISECONDS 非保留 非保留 非保留
MINUTE 非保留 非保留 非保留
MINUTES 非保留 非保留 非保留
MINUS 非保留 严格非保留 非保留
MONTH 非保留 非保留 非保留
MONTHS 非保留 非保留 非保留
MSCK 非保留 非保留 非保留
NAME 非保留 非保留 非保留
NAMESPACE 非保留 非保留 非保留
NAMESPACES 非保留 非保留 非保留
NANOSECOND 非保留 非保留 非保留
NANOSECONDS 非保留 非保留 非保留
NATURAL 保留 严格非保留 保留
NO 非保留 非保留 保留
NOT 保留 非保留 保留
NULL 保留 非保留 保留
NULLS 非保留 非保留 非保留
NUMERIC 非保留 非保留 非保留
OF 非保留 非保留 保留
OFFSET 保留 非保留 保留
ON 保留 严格非保留 保留
ONLY 保留 非保留 保留
OPTION 非保留 非保留 非保留
OPTIONS 非保留 非保留 非保留
OR 保留 非保留 保留
ORDER 保留 非保留 保留
OUT 非保留 非保留 保留
OUTER 保留 非保留 保留
OUTPUTFORMAT 非保留 非保留 非保留
OVER 非保留 非保留 非保留
OVERLAPS 保留 非保留 保留
OVERLAY 非保留 非保留 非保留
OVERWRITE 非保留 非保留 非保留
PARTITION 非保留 非保留 保留
PARTITIONED 非保留 非保留 非保留
PARTITIONS 非保留 非保留 非保留
PERCENT 非保留 非保留 非保留
PERCENTILE_CONT 保留 非保留 非保留
PERCENTILE_DISC 保留 非保留 非保留
PIVOT 非保留 非保留 非保留
PLACING 非保留 非保留 非保留
POSITION 非保留 非保留 保留
PRECEDING 非保留 非保留 非保留
PRIMARY 保留 非保留 保留
PRINCIPALS 非保留 非保留 非保留
PROPERTIES 非保留 非保留 非保留
PURGE 非保留 非保留 非保留
QUARTER 非保留 非保留 非保留
QUERY 非保留 非保留 非保留
RANGE 非保留 非保留 保留
REAL 非保留 非保留 保留
RECORDREADER 非保留 非保留 非保留
RECORDWRITER 非保留 非保留
RECOVER 非保留 非保留 非保留
REDUCE 非保留 非保留 非保留
REFERENCES 保留 非保留 保留
REFRESH 非保留 非保留 非保留
REGEXP 非保留 非保留 不是关键字
RENAME 非保留 非保留 非保留
REPAIR 非保留 非保留 非保留
REPEATABLE 非保留 非保留 非保留
REPLACE 非保留 非保留 非保留
RESET 非保留 非保留 非保留
RESPECT 非保留 非保留 非保留
RESTRICT 非保留 非保留 非保留
REVOKE 非保留 非保留 保留
RIGHT 保留 严格非保留 保留
RLIKE 非保留 非保留 非保留
ROLE 非保留 非保留 非保留
ROLES 非保留 非保留 非保留
ROLLBACK 非保留 非保留 保留
ROLLUP 非保留 非保留 保留
ROW 非保留 非保留 保留
ROWS 非保留 非保留 保留
SCHEMA 非保留 非保留 非保留
SCHEMAS 非保留 非保留 非保留
SECOND 非保留 非保留 非保留
SECONDS 非保留 非保留 非保留
SELECT 保留 非保留 保留
SEMI 非保留 严格非保留 非保留
SEPARATED 非保留 非保留 非保留
SERDE 非保留 非保留 非保留
SERDEPROPERTIES 非保留 非保留 非保留
SESSION_USER 保留 非保留 保留
SET 非保留 非保留 保留
SETS 非保留 非保留 非保留
SHORT 非保留 非保留 非保留
SHOW 非保留 非保留 非保留
SKEWED 非保留 非保留 非保留
SMALLINT 非保留 非保留 保留
SOME 保留 非保留 保留
SORT 非保留 非保留 非保留
SORTED 非保留 非保留 非保留
SOURCE 非保留 非保留 非保留
START 非保留 非保留 保留
STATISTICS 非保留 非保留 非保留
STORED 非保留 非保留 非保留
STRATIFY 非保留 非保留 非保留
STRING 非保留 非保留 非保留
STRUCT 非保留 非保留 非保留
SUBSTR 非保留 非保留 非保留
SUBSTRING 非保留 非保留 非保留
SYNC 非保留 非保留 非保留
SYSTEM_TIME 非保留 非保留 非保留
SYSTEM_VERSION 非保留 非保留 非保留
TABLE 保留 非保留 保留
TABLES 非保留 非保留 非保留
TABLESAMPLE 非保留 非保留 保留
TARGET 非保留 非保留 非保留
TBLPROPERTIES 非保留 非保留 非保留
TEMP 非保留 非保留 不是关键字
TEMPORARY 非保留 非保留 非保留
TERMINATED 非保留 非保留 非保留
THEN 保留 非保留 保留
TIME 保留 非保留 保留
TIMESTAMP 非保留 非保留 非保留
TIMESTAMP_LTZ 非保留 非保留 非保留
TIMESTAMP_NTZ 非保留 非保留 非保留
TIMESTAMPADD 非保留 非保留 非保留
TIMESTAMPDIFF 非保留 非保留 非保留
TINYINT 非保留 非保留 非保留
TO 保留 非保留 保留
TOUCH 非保留 非保留 非保留
TRAILING 保留 非保留 保留
TRANSACTION 非保留 非保留 非保留
TRANSACTIONS 非保留 非保留 非保留
TRANSFORM 非保留 非保留 非保留
TRIM 非保留 非保留 非保留
TRUE 非保留 非保留 保留
TRUNCATE 非保留 非保留 保留
TRY_CAST 非保留 非保留 非保留
TYPE 非保留 非保留 非保留
UNARCHIVE 非保留 非保留 非保留
UNBOUNDED 非保留 非保留 非保留
UNCACHE 非保留 非保留 非保留
UNION 保留 严格非保留 保留
UNIQUE 保留 非保留 保留
UNKNOWN 保留 非保留 保留
UNLOCK 非保留 非保留 非保留
UNPIVOT 非保留 非保留 非保留
UNSET 非保留 非保留 非保留
UPDATE 非保留 非保留 保留
USE 非保留 非保留 非保留
USER 保留 非保留 保留
USING 保留 严格非保留 保留
VALUES 非保留 非保留 保留
VARCHAR 非保留 非保留 保留
VERSION 非保留 非保留 非保留
VIEW 非保留 非保留 非保留
VIEWS 非保留 非保留 非保留
VOID 非保留 非保留 非保留
WEEK 非保留 非保留 非保留
WEEKS 非保留 非保留 非保留
WHEN 保留 非保留 保留
WHERE 保留 非保留 保留
WINDOW 非保留 非保留 保留
WITH 保留 非保留 保留
WITHIN 保留 非保留 保留
X 非保留 非保留 非保留
YEAR 非保留 非保留 非保留
YEARS 非保留 非保留 非保留
ZONE 非保留 非保留 非保留