ANSI 호환성
ANSI 호환성 (ANSI Compliance)
Spark SQL에서 SQL 표준을 준수하도록 하는 두 가지 옵션이 있어요: spark.sql.ansi.enabled와 spark.sql.storeAssignmentPolicy예요. 기본적으로 Spark는 ANSI 호환 모드를 사용해서, 잘못된 연산이 있을 때 null 대신 런타임 예외를 던지고, ANSI 방식의 타입 변환 규칙을 적용해요. 이 문서에서 ANSI 모드가 산술 연산, 타입 변환, SQL 파싱에 주는 영향을 차근차근 살펴볼게요.
출처: 문서
본문
Spark SQL에서는 SQL 표준을 준수하기 위한 두 가지 옵션이 있어요: spark.sql.ansi.enabled와 spark.sql.storeAssignmentPolicy (자세한 내용은 아래 표를 참고하세요).
기본적으로 spark.sql.ansi.enabled는 true이고, Spark SQL은 Hive 호환 방식 대신 ANSI 호환(dialect) 방식을 사용해요. 예를 들어 SQL 연산자/함수에 대한 입력이 유효하지 않으면, Spark는 null 결과를 반환하는 대신 런타임에 예외를 던져요. 일부 ANSI dialect 기능은 ANSI SQL 표준에서 직접 온 것이 아닐 수 있지만, 그 동작 방식은 ANSI SQL의 스타일과 일치해요.
또한 Spark SQL은 테이블에 행을 삽입할 때 암시적 캐스팅 동작을 제어하는 별도의 옵션을 가지고 있어요. 이 캐스팅 동작은 표준에서 store assignment 규칙으로 정의돼요.
기본적으로 spark.sql.storeAssignmentPolicy는 ANSI이고, Spark SQL은 ANSI store assignment 규칙을 준수해요.
| 속성 이름 (Property Name) | 기본값 (Default) | 의미 (Meaning) | 도입 버전 (Since Version) |
|---|---|---|---|
spark.sql.ansi.enabled |
true | true일 때 Spark는 ANSI SQL 사양을 따르려 해요: 1. Spark SQL은 정수 오버플로 오류, 문자열 파싱 오류 등을 포함한 잘못된 연산에 대해 런타임 예외를 던져요. 2. Spark는 데이터 타입 간 충돌을 해결하기 위해 다른 타입 강제 변환(type coercion) 규칙을 사용해요. 그 규칙은 데이터 타입 우선순위에 일관되게 기반해요. | 3.0.0 |
spark.sql.storeAssignmentPolicy |
ANSI | 다른 데이터 타입의 컬럼에 값을 삽입할 때 Spark는 타입 변환을 수행해요. 현재 타입 강제 변환 규칙에 대해 3가지 정책을 지원해요: ANSI, legacy, strict. 1. ANSI 정책에서는 Spark가 ANSI SQL에 따라 타입 강제 변환을 수행해요. 실제로는 PostgreSQL과 대부분 동일하게 동작해요. string→int나 double→boolean 같은 비합리적인 타입 변환은 허용하지 않아요. 숫자 타입 컬럼에 삽입할 때 값이 대상 타입의 범위를 벗어나면 오버플로 오류가 발생해요. 2. legacy 정책에서는 유효한 Cast라면 타입 강제 변환을 허용해서, 매우 느슨해요. 예를 들어 string→int나 double→boolean 변환이 허용돼요. 이것은 Spark 2.x에서의 유일한 동작이며 Hive와 호환돼요. 3. strict 정책에서는 타입 강제 변환에서 어떤 정밀도 손실이나 데이터 잘림(truncation)도 허용하지 않아요. 예를 들어 double→int나 decimal→double 변환은 허용되지 않아요. | 3.0.0 |
다음 절들에서는 ANSI 모드가 활성화됐을 때 산술 연산, 타입 변환, SQL 파싱의 동작 변화를 다룰게요. Spark SQL의 타입 변환에는 세 가지 종류가 있는데, 이 문서에서 하나씩 소개할게요: cast, store assignment, type coercion.
산술 연산 (Arithmetic Operations)
Spark SQL에서 기본적으로 Spark는 interval 타입과 숫자 타입의 오버플로에 대해 런타임에 산술 예외(arithmetic exception)를 던져요. spark.sql.ansi.enabled가 false라면, decimal 타입은 null 값을 생성하고 다른 숫자 타입들은 Java/Scala 프로그램에서의 대응 연산과 같은 방식으로 동작해요 (예: 두 정수의 합이 표현 가능한 최대값을 넘으면 결과가 음수가 됨). 이것은 Spark 3 이전의 동작이에요.
-- `spark.sql.ansi.enabled=true`
SELECT 2147483647 + 1;
org.apache.spark.SparkArithmeticException: [ARITHMETIC_OVERFLOW] integer overflow. Use 'try_add' to tolerate overflow and return NULL instead. If necessary set spark.sql.ansi.enabled to "false" to bypass this error.
== SQL(line 1, position 8) ==
SELECT 2147483647 + 1
^^^^^^^^^^^^^^
SELECT abs(-2147483648);
org.apache.spark.SparkArithmeticException: [ARITHMETIC_OVERFLOW] integer overflow. If necessary set spark.sql.ansi.enabled to "false" to bypass this error.
-- `spark.sql.ansi.enabled=false`
SELECT 2147483647 + 1;
+----------------+
|(2147483647 + 1)|
+----------------+
| -2147483648|
+----------------+
SELECT abs(-2147483648);
+----------------+
|abs(-2147483648)|
+----------------+
| -2147483648|
+----------------+
Cast
spark.sql.ansi.enabled가 true로 설정되면, CAST 구문에 의한 명시적 캐스팅은 표준에 정의된 잘못된 캐스트 패턴(예: 문자열에서 정수로의 캐스트)에 대해 런타임 예외를 던져요.
또한 ANSI SQL 모드는 ANSI 모드가 꺼져 있을 때 허용되던 다음과 같은 타입 변환을 금지해요:
- Numeric <=> Binary
- Date <=> Boolean
- Timestamp <=> Boolean
- Date => Numeric
CAST 표현식에서 소스와 대상 데이터 타입의 유효한 조합은 다음 표로 주어져요. “Y”는 해당 조합이 제약 없이 구문상 유효함을, “N”은 유효하지 않음을 나타내요.
| Source\Target | Numeric | String | Date | Time | Timestamp | Timestamp_NTZ | Interval | Boolean | Binary | Array | Map | Struct |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Numeric | Y | Y | N | N | Y | N | Y | Y | N | N | N | N |
| String | Y | Y | Y | Y | Y | Y | Y | Y | Y | N | N | N |
| Date | N | Y | Y | N | Y | Y | N | N | N | N | N | N |
| Time | N | Y | N | Y | N | N | N | N | N | N | N | N |
| Timestamp | Y | Y | Y | N | Y | Y | N | N | N | N | N | N |
| Timestamp_NTZ | N | Y | Y | N | Y | Y | N | N | N | N | N | N |
| Interval | Y | Y | N | N | N | N | Y | N | N | N | N | N |
| Boolean | Y | Y | N | N | N | N | N | Y | N | N | N | N |
| Binary | N | Y | N | N | N | N | N | N | Y | N | N | N |
| Array | N | Y | N | N | N | N | N | N | N | Y | N | N |
| Map | N | Y | N | N | N | N | N | N | N | N | Y | N |
| Struct | N | Y | N | N | N | N | N | N | N | N | N | Y |
위 표에서 새 구문의 모든 CAST는 빨간색 Y로 표시되어 있어요:
- CAST(Numeric AS Numeric): 값이 대상 타입의 범위를 벗어나면 오버플로 예외를 발생시켜요.
- CAST(String AS (Numeric/Date/Timestamp/Timestamp_NTZ/Interval/Boolean)): 값이 대상 타입으로 파싱될 수 없으면 런타임 예외를 발생시켜요.
- CAST(Timestamp AS Numeric): epoch 이후 초(seconds)가 대상 타입의 범위를 벗어나면 오버플로 예외를 발생시켜요.
- CAST(Numeric AS Timestamp): 숫자 값에 1000000(초당 마이크로초)을 곱한 값이 Long 타입의 범위를 벗어나면 오버플로 예외를 발생시켜요.
- CAST(Array AS Array): 요소 변환 중 오류가 있으면 예외를 발생시켜요.
- CAST(Map AS Map): 키와 값 변환 중 오류가 있으면 예외를 발생시켜요.
- CAST(Struct AS Struct): struct 필드 변환 중 오류가 있으면 예외를 발생시켜요.
- CAST(Numeric AS String): decimal 값을 문자열로 캐스팅할 때 지수가 필요하면 과학적 표기법 대신 항상 일반 문자열 표현을 사용해요.
- CAST(Interval AS Numeric): day-time interval의 마이크로초 수 또는 year-month interval의 월 수가 대상 타입의 범위를 벗어나면 오버플로 예외를 발생시켜요.
- CAST(Numeric AS Interval): 숫자 값에 대상 interval의 끝 단위(end-unit)를 곱한 값이 year-month interval은 Int 타입, day-time interval은 Long 타입의 범위를 벗어나면 오버플로 예외를 발생시켜요.
-- Examples of explicit casting
-- `spark.sql.ansi.enabled=true` (This is a default behaviour)
SELECT CAST('a' AS INT);
org.apache.spark.SparkNumberFormatException: [CAST_INVALID_INPUT] The value 'a' of the type "STRING" cannot be cast to "INT" because it is malformed. Correct the value as per the syntax, or change its target type. Use `try_cast` to tolerate malformed input and return NULL instead.
== SQL(line 1, position 8) ==
SELECT CAST('a' AS INT)
^^^^^^^^^^^^^^^^
SELECT CAST(2147483648L AS INT);
org.apache.spark.SparkArithmeticException: [CAST_OVERFLOW] The value 2147483648L of the type "BIGINT" cannot be cast to "INT" due to an overflow. Use `try_cast` to tolerate overflow and return NULL instead.
SELECT CAST(DATE'2020-01-01' AS INT);
org.apache.spark.sql.AnalysisException: cannot resolve 'CAST(DATE '2020-01-01' AS INT)' due to data type mismatch: cannot cast date to int.
To convert values from date to int, you can use function UNIX_DATE instead.
-- `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|
+------------------------------+
-- Examples of store assignment rules
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] Cannot write incompatible data for table `spark_catalog`.`default`.`t`: Cannot safely cast `v`: "STRING" to "INT".
-- `spark.sql.storeAssignmentPolicy=LEGACY` (This is a legacy behaviour until Spark 2.x)
INSERT INTO t VALUES ('1');
SELECT * FROM t;
+---+
| v|
+---+
| 1|
+---+
캐스트에서의 반올림 (Rounding in cast)
소수부(fraction)가 있는 decimal을 INTERVAL HOUR TO SECOND처럼 SECOND를 끝 단위(end-unit)로 하는 interval 타입으로 캐스팅할 때, Spark는 두 이웃 값이 등거리인 경우를 제외하고는 "가장 가까운 이웃(nearest neighbor)" 쪽으로 반올림해요. 등거리인 경우에는 올림(round up)해요.
Store assignment
앞서 언급했듯이, spark.sql.storeAssignmentPolicy가 ANSI(기본값)로 설정되면 Spark SQL은 테이블 삽입 시 ANSI store assignment 규칙을 준수해요. 테이블 삽입에서 소스와 대상 데이터 타입의 유효한 조합은 다음 표로 주어져요.
| Source\Target | Numeric | String | Date | Time | Timestamp | Timestamp_NTZ | Interval | Boolean | Binary | Array | Map | Struct |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Numeric | Y | Y | N | N | N | N | N | N | N | N | N | N |
| String | N | Y | N | Y | N | N | N | N | N | N | N | N |
| Date | N | Y | Y | N | Y | Y | N | N | N | N | N | N |
| Time | N | Y | N | Y | N | N | N | N | N | N | N | N |
| Timestamp | N | Y | Y | N | Y | Y | N | N | N | N | N | N |
| Timestamp_NTZ | N | Y | Y | N | Y | Y | N | N | N | N | N | N |
| Interval | N | Y | N | N | N | N | N* | N | N | N | N | N |
| Boolean | N | Y | N | N | N | N | N | Y | N | N | N | N |
| Binary | N | Y | N | N | N | N | N | N | Y | N | N | N |
| Array | N | N | N | N | N | N | N | N | N | Y** | N | N |
| Map | N | N | N | N | N | N | N | N | N | N | Y** | N |
| Struct | N | N | N | N | N | N | N | N | N | N | N | Y** |
* Spark는 interval 타입 테이블 컬럼을 지원하지 않아요.
** Array/Map/Struct 타입의 경우 데이터 타입 검사 규칙이 그 구성 요소(element)에도 재귀적으로 적용돼요.
테이블 삽입 중에 숫자 값 오버플로가 발생하면 Spark는 예외를 던져요.
CREATE TABLE test(i INT);
INSERT INTO test VALUES (2147483648L);
org.apache.spark.SparkArithmeticException: [CAST_OVERFLOW_IN_TABLE_INSERT] Fail to insert a value of "BIGINT" type into the "INT" type column `i` due to an overflow. Use `try_cast` on the input value to tolerate overflow and return NULL instead.
타입 강제 변환 (Type coercion)
타입 승격과 우선순위 (Type Promotion and Precedence)
spark.sql.ansi.enabled가 true로 설정되면, Spark SQL은 데이터 타입 간의 충돌을 해결하는 방법을 지배하는 여러 규칙을 사용해요. 이 충돌 해결의 핵심은 타입 우선순위 목록(Type Precedence List)인데, 주어진 데이터 타입의 값이 다른 데이터 타입으로 암시적으로 승격될 수 있는지를 정의해요.
| 데이터 타입 (Data type) | 우선순위 목록 (precedence list, 가장 좁은 것부터 가장 넓은 것까지) |
|---|---|
| Byte | Byte -> Short -> Int -> Long -> Decimal -> Float* -> Double |
| Short | Short -> Int -> Long -> Decimal-> Float* -> Double |
| Int | Int -> Long -> Decimal -> Float* -> Double |
| Long | Long -> Decimal -> Float* -> Double |
| Decimal | Decimal -> Float* -> Double |
| Float | Float -> Double |
| Double | Double |
| Date | Date -> Timestamp_NTZ -> Timestamp |
| Time | Time |
| Timestamp | Timestamp |
| String | String, Long -> Double, Date -> Timestamp_NTZ -> Timestamp , Boolean, Binary ** |
| Binary | Binary |
| Boolean | Boolean |
| Interval | Interval |
| Map | Map*** |
| Array | Array*** |
| Struct | Struct*** |
* 최소 공통 타입(least common type) 해석에서 정밀도 손실을 피하기 위해 float는 건너뛰어요.
** String은 여러 종류의 데이터 타입으로 승격될 수 있어요. Byte/Short/Int/Decimal/Float는 이 우선순위 목록에 없다는 점에 주의하세요. Byte/Short/Int와 String 사이의 최소 공통 타입은 Long이고, Decimal/Float와 String 사이의 최소 공통 타입은 Double이에요.
*** 복합 타입(complex type)의 경우 우선순위 규칙이 그 구성 요소(element)에 재귀적으로 적용돼요.
타입이 없는(untyped) NULL에는 특별한 규칙이 적용돼요. NULL은 다른 어떤 타입으로도 승격될 수 있어요.
이것은 우선순위 목록을 방향 트리로 그린 도표예요:

최소 공통 타입 해석 (Least Common Type Resolution)
타입 집합에서의 최소 공통 타입(least common type)은 그 타입 집합의 모든 요소가 우선순위 목록을 통해 도달할 수 있는 가장 좁은 타입이에요.
최소 공통 타입 해석은 다음에 사용돼요:
coalesce,least,greatest처럼 여러 매개변수가 공통 인자 타입을 기대하는 함수의 인자 타입을 도출하는 데 사용돼요.- 산술 연산이나 비교 같은 연산자의 피연산자(operand) 타입을 도출하는 데 사용돼요.
- case 표현식 같은 표현식의 결과 타입을 도출하는 데 사용돼요.
- array와 map 생성자(constructor)의 element, key, value 타입을 도출하는 데 사용돼요. 최소 공통 타입이 FLOAT로 해석되면 특별한 규칙이 적용돼요. float 타입 값에서, 타입 중 하나라도 INT, BIGINT, DECIMAL이면 자릿수 손실을 피하기 위해 최소 공통 타입이 DOUBLE로 올려져요(pushed).
Decimal 타입은 여기서 좀 더 복잡한데, 단순한 타입이 아니라 precision과 scale이라는 매개변수를 가지기 때문이에요. decimal(precision, scale)은 값이 정수부(integral part)에 최대 precision - scale 자리, 소수부(fractional part)에 scale 자리를 가질 수 있음을 의미해요. decimal 타입들 사이의 최소 공통 타입은 모든 값을 표현하기 위해 정수부와 소수부 양쪽에 충분한 자릿수를 가져야 해요. 더 정확히는 decimal(p1, s1)과 decimal(p2, s2) 사이의 최소 공통 타입은 max(s1, s2)의 scale과 max(s1, s2) + max(p1 - s1, p2 - s2)의 precision을 가져요. 하지만 Spark의 decimal 타입은 최대 precision이 38이에요. 최종 decimal 타입이 더 많은 precision을 필요로 하면 잘림(truncation)을 해야 해요. 정수부의 자릿수가 더 중요하므로 Spark는 소수부의 자릿수를 먼저 잘라요. 예를 들어 decimal(48, 20)은 decimal(38, 10)으로 줄어들어요.
참고로 산술 연산은 decimal 입력에 대한 최소 공통 타입을 계산하는 특별한 규칙이 있어요:
| 연산 (Operation) | 결과 precision (Result precision) | 결과 scale (Result scale) |
|---|---|---|
| e1 + e2 | max(s1, s2) + max(p1 - s1, p2 - s2) + 1 | max(s1, s2) |
| e1 - e2 | max(s1, s2) + max(p1 - s1, p2 - s2) + 1 | max(s1, s2) |
| e1 * e2 | p1 + p2 + 1 | s1 + s2 |
| e1 / e2 | p1 - s1 + s2 + max(6, s1 + p2 + 1) | max(6, s1 + p2 + 1) |
| e1 % e2 | min(p1 - s1, p2 - s2) + max(s1, s2) | max(s1, s2) |
잘림 규칙도 산술 연산에서는 다르게 적용돼요. 소수부에 최소 6자리를 유지하는데, 이는 scale을 6까지만 줄일 수 있음을 의미해요. 이 경우 오버플로가 발생할 수 있어요.
-- The coalesce function accepts any set of argument types as long as they share a least common type.
-- The result type is the least common type of the arguments.
> SET spark.sql.ansi.enabled=true;
> SELECT typeof(coalesce(1Y, 1L, NULL));
BIGINT
> SELECT typeof(coalesce(1, DATE'2020-01-01'));
Error: Incompatible types [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 함수 (SQL Functions)
함수 호출 (Function invocation)
ANSI 모드(spark.sql.ansi.enabled=true)에서 Spark SQL의 함수 호출은:
- 일반적으로, 입력 값을 SQL 함수의 선언된 매개변수 타입으로 저장하는 것처럼
Store assignment규칙을 따라요. - 타입이 없는 NULL에는 특별한 규칙이 적용돼요. NULL은 다른 어떤 타입으로도 승격될 수 있어요.
> SET spark.sql.ansi.enabled=true;
-- implicitly cast Int to String type
> SELECT concat('total number: ', 1);
total number: 1
-- implicitly cast Timestamp to Date type
> select datediff(now(), current_date);
0
-- implicitly cast String to Double type
> SELECT ceil('0.1');
1
-- special rule: implicitly cast NULL to Date type
> SELECT year(null);
NULL
> CREATE TABLE t(s string);
-- Can't store String column as Numeric types.
> SELECT ceil(s) from t;
Error in query: cannot resolve 'CEIL(spark_catalog.default.t.s)' due to data type mismatch
-- Can't store String column as Date type.
> select year(s) from t;
Error in query: cannot resolve 'year(spark_catalog.default.t.s)' due to data type mismatch
동작이 다른 함수들 (Functions with different behaviors)
일부 SQL 함수의 동작은 ANSI 모드(spark.sql.ansi.enabled=true)에서 달라질 수 있어요.
size: 이 함수는 null 입력에 대해 null을 반환해요.element_at:- 이 함수는 유효하지 않은 인덱스를 사용하면
ArrayIndexOutOfBoundsException을 던져요.
- 이 함수는 유효하지 않은 인덱스를 사용하면
elt: 이 함수는 유효하지 않은 인덱스를 사용하면ArrayIndexOutOfBoundsException을 던져요.parse_url: 이 함수는 입력 문자열이 유효한 url이 아니면IllegalArgumentException을 던져요.to_date: 이 함수는 입력 문자열을 파싱할 수 없거나 패턴 문자열이 유효하지 않으면 예외와 함께 실패해야 해요.to_timestamp: 이 함수는 입력 문자열을 파싱할 수 없거나 패턴 문자열이 유효하지 않으면 예외와 함께 실패해야 해요.unix_timestamp: 이 함수는 입력 문자열을 파싱할 수 없거나 패턴 문자열이 유효하지 않으면 예외와 함께 실패해야 해요.to_unix_timestamp: 이 함수는 입력 문자열을 파싱할 수 없거나 패턴 문자열이 유효하지 않으면 예외와 함께 실패해야 해요.make_date: 이 함수는 결과 날짜가 유효하지 않으면 예외와 함께 실패해야 해요.make_timestamp: 이 함수는 결과 타임스탬프가 유효하지 않으면 예외와 함께 실패해야 해요.make_interval: 이 함수는 결과 interval이 유효하지 않으면 예외와 함께 실패해야 해요.next_day: 이 함수는 입력이 유효한 요일(day of week)이 아니면IllegalArgumentException을 던져요.
SQL 연산자 (SQL Operators)
일부 SQL 연산자의 동작은 ANSI 모드(spark.sql.ansi.enabled=true)에서 달라질 수 있어요.
array_col[index]: 이 연산자는 유효하지 않은 인덱스를 사용하면ArrayIndexOutOfBoundsException을 던져요.
ANSI 모드에 유용한 함수 (Useful Functions for ANSI Mode)
ANSI 모드가 켜져 있으면 잘못된 연산에 대해 예외가 발생해요. 다음과 같은 SQL 함수를 사용해 그러한 예외를 억제할 수 있어요.
try_cast:CAST와 동일하지만, 런타임 오류 시 예외를 던지는 대신NULL결과를 반환해요.try_add: 더하기 연산자+와 동일하지만, 정수 값 오버플로 시 예외를 던지는 대신NULL결과를 반환해요.try_subtract: 빼기 연산자-와 동일하지만, 정수 값 오버플로 시 예외를 던지는 대신NULL결과를 반환해요.try_multiply: 곱하기 연산자*와 동일하지만, 정수 값 오버플로 시 예외를 던지는 대신NULL결과를 반환해요.try_divide: 나누기 연산자/와 동일하지만, 0으로 나눌 때 예외를 던지는 대신NULL결과를 반환해요.try_mod: 나머지 연산자%와 동일하지만, 0으로 나눌 때 예외를 던지는 대신NULL결과를 반환해요.try_sum:sum함수와 동일하지만, 정수/decimal/interval 값 오버플로 시 예외를 던지는 대신NULL결과를 반환해요.try_avg:avg함수와 동일하지만, decimal/interval 값 오버플로 시 예외를 던지는 대신NULL결과를 반환해요.try_element_at:element_at함수와 동일하지만, 배열 인덱스가 범위를 벗어날 때 예외를 던지는 대신NULL결과를 반환해요.try_to_timestamp:to_timestamp함수와 동일하지만, 문자열 파싱 오류 시 예외를 던지는 대신NULL결과를 반환해요.try_parse_url:parse_url함수와 동일하지만, url 파싱 오류 시 예외를 던지는 대신NULL결과를 반환해요.try_make_timestamp:make_timestamp함수와 동일하지만, 오류 시 예외를 던지는 대신NULL결과를 반환해요.try_make_timestamp_ltz:make_timestamp_ltz함수와 동일하지만, 오류 시 예외를 던지는 대신NULL결과를 반환해요.try_make_timestamp_ntz:make_timestamp_ntz함수와 동일하지만, 오류 시 예외를 던지는 대신NULL결과를 반환해요.try_make_interval:make_interval함수와 동일하지만, 유효하지 않은 interval 시 예외를 던지는 대신NULL결과를 반환해요.try_to_time:to_time함수와 동일하지만, 문자열 파싱 오류 시 예외를 던지는 대신NULL결과를 반환해요.try_to_date:to_date함수와 동일하지만, 문자열 파싱 오류 시 예외를 던지는 대신NULL결과를 반환해요.
SQL 키워드 (SQL Keywords, 선택 사항, 기본적으로 비활성화)
spark.sql.ansi.enabled와 spark.sql.ansi.enforceReservedKeywords가 둘 다 true일 때 Spark SQL은 ANSI 모드 파서(parser)를 사용해요.
ANSI 모드 파서에서 Spark SQL은 두 종류의 키워드를 가져요:
- 비예약 키워드(Non-reserved keywords): 특정 문맥에서만 특별한 의미를 갖고, 다른 문맥에서는 식별자로 사용될 수 있는 키워드예요. 예를 들어
EXPLAIN SELECT ...는 명령이지만, EXPLAIN은 다른 곳에서는 식별자로 사용될 수 있어요. - 예약 키워드(Reserved keywords): 예약되어 있어서 테이블, 뷰, 컬럼, 함수, 별칭(alias) 등의 식별자로 사용할 수 없는 키워드예요.
기본 파서로는 Spark SQL은 두 종류의 키워드를 가져요:
- 비예약 키워드(Non-reserved keywords): ANSI 모드가 활성화됐을 때와 같은 정의예요.
- 엄격한 비예약 키워드(Strict-non-reserved keywords): 비예약 키워드의 엄격한 버전으로, 테이블 별칭으로 사용할 수 없어요.
기본적으로 spark.sql.ansi.enforceReservedKeywords는 false예요.
아래는 Spark SQL의 모든 키워드 목록이에요.
| 키워드 (Keyword) | Spark SQL ANSI 모드 | Spark SQL 비ANSI 모드 | SQL-2016 |
|---|---|---|---|
| ADD | non-reserved | non-reserved | non-reserved |
| AFTER | non-reserved | non-reserved | non-reserved |
| AGGREGATE | non-reserved | non-reserved | non-reserved |
| ALL | reserved | non-reserved | reserved |
| ALTER | non-reserved | non-reserved | reserved |
| ALWAYS | non-reserved | non-reserved | non-reserved |
| ANALYZE | non-reserved | non-reserved | non-reserved |
| AND | reserved | non-reserved | reserved |
| ANTI | non-reserved | strict-non-reserved | non-reserved |
| ANY | reserved | non-reserved | reserved |
| ANY_VALUE | non-reserved | non-reserved | non-reserved |
| APPROX | non-reserved | non-reserved | non-reserved |
| ARCHIVE | non-reserved | non-reserved | non-reserved |
| ARRAY | non-reserved | non-reserved | reserved |
| AS | reserved | non-reserved | reserved |
| ASC | non-reserved | non-reserved | non-reserved |
| ASENSITIVE | non-reserved | non-reserved | non-reserved |
| AT | non-reserved | non-reserved | reserved |
| ATOMIC | non-reserved | non-reserved | non-reserved |
| AUTHORIZATION | reserved | non-reserved | reserved |
| BEGIN | non-reserved | non-reserved | non-reserved |
| BERNOULLI | non-reserved | non-reserved | non-reserved |
| BETWEEN | non-reserved | non-reserved | reserved |
| BIGINT | non-reserved | non-reserved | reserved |
| BINARY | non-reserved | non-reserved | reserved |
| BINDING | non-reserved | non-reserved | non-reserved |
| BOOLEAN | non-reserved | non-reserved | reserved |
| BOTH | reserved | non-reserved | reserved |
| BUCKET | non-reserved | non-reserved | non-reserved |
| BUCKETS | non-reserved | non-reserved | non-reserved |
| BY | non-reserved | non-reserved | reserved |
| BYTE | non-reserved | non-reserved | non-reserved |
| CACHE | non-reserved | non-reserved | non-reserved |
| CALL | reserved | non-reserved | reserved |
| CALLED | non-reserved | non-reserved | non-reserved |
| CASCADE | non-reserved | non-reserved | non-reserved |
| CASE | reserved | non-reserved | reserved |
| CAST | reserved | non-reserved | reserved |
| CATALOG | non-reserved | non-reserved | non-reserved |
| CATALOGS | non-reserved | non-reserved | non-reserved |
| CHANGE | non-reserved | non-reserved | non-reserved |
| CHANGES | non-reserved | non-reserved | non-reserved |
| CHAR | non-reserved | non-reserved | reserved |
| CHARACTER | non-reserved | non-reserved | reserved |
| CHECK | reserved | non-reserved | reserved |
| CLEAR | non-reserved | non-reserved | non-reserved |
| CLOSE | non-reserved | non-reserved | non-reserved |
| CLUSTER | non-reserved | non-reserved | non-reserved |
| CLUSTERED | non-reserved | non-reserved | non-reserved |
| CODEGEN | non-reserved | non-reserved | non-reserved |
| COLLATE | reserved | non-reserved | reserved |
| COLLATION | reserved | non-reserved | reserved |
| COLLATIONS | reserved | non-reserved | non-reserved |
| COLLECTION | non-reserved | non-reserved | non-reserved |
| COLUMN | reserved | non-reserved | reserved |
| COLUMNS | non-reserved | non-reserved | non-reserved |
| COMMENT | non-reserved | non-reserved | non-reserved |
| COMMIT | non-reserved | non-reserved | reserved |
| COMPACT | non-reserved | non-reserved | non-reserved |
| COMPACTIONS | non-reserved | non-reserved | non-reserved |
| COMPENSATION | non-reserved | non-reserved | non-reserved |
| COMPUTE | non-reserved | non-reserved | non-reserved |
| CONCATENATE | non-reserved | non-reserved | non-reserved |
| CONDITION | non-reserved | non-reserved | non-reserved |
| CONSTRAINT | reserved | non-reserved | reserved |
| CONTAINS | non-reserved | non-reserved | non-reserved |
| CONTINUE | non-reserved | non-reserved | non-reserved |
| COST | non-reserved | non-reserved | non-reserved |
| CREATE | reserved | non-reserved | reserved |
| CROSS | reserved | strict-non-reserved | reserved |
| CUBE | non-reserved | non-reserved | reserved |
| CURRENT | non-reserved | non-reserved | reserved |
| CURRENT_DATABASE | non-reserved | non-reserved | non-reserved |
| CURRENT_DATE | reserved | non-reserved | reserved |
| CURRENT_PATH | reserved | non-reserved | reserved |
| CURRENT_SCHEMA | reserved | non-reserved | reserved |
| CURRENT_TIME | reserved | non-reserved | reserved |
| CURRENT_TIMESTAMP | reserved | non-reserved | reserved |
| CURRENT_USER | reserved | non-reserved | reserved |
| CURSOR | non-reserved | non-reserved | non-reserved |
| DATA | non-reserved | non-reserved | non-reserved |
| DATE | non-reserved | non-reserved | reserved |
| DATABASE | non-reserved | non-reserved | non-reserved |
| DATABASES | non-reserved | non-reserved | non-reserved |
| DATEADD | non-reserved | non-reserved | non-reserved |
| DATE_ADD | non-reserved | non-reserved | non-reserved |
| DATEDIFF | non-reserved | non-reserved | non-reserved |
| DATE_DIFF | non-reserved | non-reserved | non-reserved |
| DAY | non-reserved | non-reserved | non-reserved |
| DAYS | non-reserved | non-reserved | non-reserved |
| DAYOFYEAR | non-reserved | non-reserved | non-reserved |
| DBPROPERTIES | non-reserved | non-reserved | non-reserved |
| DEC | non-reserved | non-reserved | reserved |
| DECIMAL | non-reserved | non-reserved | reserved |
| DECLARE | non-reserved | non-reserved | non-reserved |
| DEFAULT | non-reserved | non-reserved | non-reserved |
| DEFINED | non-reserved | non-reserved | non-reserved |
| DEFINER | non-reserved | non-reserved | non-reserved |
| DEFAULT_PATH | non-reserved | non-reserved | not a keyword |
| DELAY | non-reserved | non-reserved | non-reserved |
| DELETE | non-reserved | non-reserved | reserved |
| DELIMITED | non-reserved | non-reserved | non-reserved |
| DESC | non-reserved | non-reserved | non-reserved |
| DESCRIBE | non-reserved | non-reserved | reserved |
| DETERMINISTIC | non-reserved | non-reserved | reserved |
| DFS | non-reserved | non-reserved | non-reserved |
| DIRECTORIES | non-reserved | non-reserved | non-reserved |
| DIRECTORY | non-reserved | non-reserved | non-reserved |
| DISTANCE | non-reserved | non-reserved | non-reserved |
| DISTINCT | reserved | non-reserved | reserved |
| DISTRIBUTE | non-reserved | non-reserved | non-reserved |
| DIV | non-reserved | non-reserved | not a keyword |
| DO | non-reserved | non-reserved | non-reserved |
| DOUBLE | non-reserved | non-reserved | reserved |
| DROP | non-reserved | non-reserved | reserved |
| ELSE | reserved | non-reserved | reserved |
| ELSEIF | non-reserved | non-reserved | non-reserved |
| END | reserved | non-reserved | reserved |
| ENFORCED | non-reserved | non-reserved | non-reserved |
| ESCAPE | reserved | non-reserved | reserved |
| ESCAPED | non-reserved | non-reserved | non-reserved |
| EVOLUTION | non-reserved | non-reserved | non-reserved |
| EXACT | non-reserved | non-reserved | non-reserved |
| EXCEPT | reserved | strict-non-reserved | reserved |
| EXCHANGE | non-reserved | non-reserved | non-reserved |
| EXCLUDE | non-reserved | non-reserved | non-reserved |
| EXCLUSIVE | non-reserved | non-reserved | non-reserved |
| EXECUTE | reserved | non-reserved | reserved |
| EXISTS | non-reserved | non-reserved | reserved |
| EXIT | non-reserved | non-reserved | non-reserved |
| EXPLAIN | non-reserved | non-reserved | non-reserved |
| EXPORT | non-reserved | non-reserved | non-reserved |
| EXTEND | non-reserved | non-reserved | non-reserved |
| EXTENDED | non-reserved | non-reserved | non-reserved |
| EXTERNAL | non-reserved | non-reserved | reserved |
| EXTRACT | non-reserved | non-reserved | reserved |
| FALSE | reserved | non-reserved | reserved |
| FETCH | reserved | non-reserved | reserved |
| FIELDS | non-reserved | non-reserved | non-reserved |
| FILTER | reserved | non-reserved | reserved |
| FILEFORMAT | non-reserved | non-reserved | non-reserved |
| FIRST | non-reserved | non-reserved | non-reserved |
| FLOAT | non-reserved | non-reserved | reserved |
| FLOW | non-reserved | non-reserved | non-reserved |
| FOLLOWING | non-reserved | non-reserved | non-reserved |
| FOR | reserved | non-reserved | reserved |
| FOREIGN | reserved | non-reserved | reserved |
| FORMAT | non-reserved | non-reserved | non-reserved |
| FORMATTED | non-reserved | non-reserved | non-reserved |
| FOUND | non-reserved | non-reserved | non-reserved |
| FROM | reserved | non-reserved | reserved |
| FULL | reserved | strict-non-reserved | reserved |
| FUNCTION | non-reserved | non-reserved | reserved |
| FUNCTIONS | non-reserved | non-reserved | non-reserved |
| GENERATED | non-reserved | non-reserved | non-reserved |
| GEOGRAPHY | non-reserved | non-reserved | non-reserved |
| GEOMETRY | non-reserved | non-reserved | non-reserved |
| GLOBAL | non-reserved | non-reserved | reserved |
| GRANT | reserved | non-reserved | reserved |
| GROUP | reserved | non-reserved | reserved |
| GROUPING | non-reserved | non-reserved | reserved |
| HANDLER | non-reserved | non-reserved | non-reserved |
| HAVING | reserved | non-reserved | reserved |
| HOUR | non-reserved | non-reserved | non-reserved |
| HOURS | non-reserved | non-reserved | non-reserved |
| IDENTIFIER | non-reserved | non-reserved | non-reserved |
| IDENTIFIED | non-reserved | non-reserved | non-reserved |
| IDENTITY | non-reserved | non-reserved | non-reserved |
| IF | non-reserved | non-reserved | not a keyword |
| IGNORE | non-reserved | non-reserved | non-reserved |
| IMMEDIATE | non-reserved | non-reserved | non-reserved |
| IMPORT | non-reserved | non-reserved | non-reserved |
| IN | reserved | non-reserved | reserved |
| INCLUDE | non-reserved | non-reserved | non-reserved |
| INCLUSIVE | non-reserved | non-reserved | non-reserved |
| INCREMENT | non-reserved | non-reserved | non-reserved |
| INDEX | non-reserved | non-reserved | non-reserved |
| INDEXES | non-reserved | non-reserved | non-reserved |
| INNER | reserved | strict-non-reserved | reserved |
| INPATH | non-reserved | non-reserved | non-reserved |
| INPUT | non-reserved | non-reserved | non-reserved |
| INPUTFORMAT | non-reserved | non-reserved | non-reserved |
| INSERT | non-reserved | non-reserved | reserved |
| INSENSITIVE | non-reserved | non-reserved | non-reserved |
| INT | non-reserved | non-reserved | reserved |
| INTEGER | non-reserved | non-reserved | reserved |
| INTERSECT | reserved | strict-non-reserved | reserved |
| INTERVAL | non-reserved | non-reserved | reserved |
| INTO | reserved | non-reserved | reserved |
| INVOKER | non-reserved | non-reserved | non-reserved |
| IS | reserved | non-reserved | reserved |
| ITEMS | non-reserved | non-reserved | non-reserved |
| ITERATE | non-reserved | non-reserved | non-reserved |
| JOIN | reserved | strict-non-reserved | reserved |
| JSON | non-reserved | non-reserved | non-reserved |
| KEY | non-reserved | non-reserved | non-reserved |
| KEYS | non-reserved | non-reserved | non-reserved |
| LANGUAGE | non-reserved | non-reserved | reserved |
| LAST | non-reserved | non-reserved | non-reserved |
| LATERAL | reserved | strict-non-reserved | reserved |
| LAZY | non-reserved | non-reserved | non-reserved |
| LEADING | reserved | non-reserved | reserved |
| LEAVE | non-reserved | non-reserved | non-reserved |
| LEFT | reserved | strict-non-reserved | reserved |
| LEVEL | non-reserved | non-reserved | non-reserved |
| LIKE | non-reserved | non-reserved | reserved |
| ILIKE | non-reserved | non-reserved | non-reserved |
| LIMIT | non-reserved | non-reserved | non-reserved |
| LINES | non-reserved | non-reserved | non-reserved |
| LIST | non-reserved | non-reserved | non-reserved |
| LOAD | non-reserved | non-reserved | non-reserved |
| LOCAL | non-reserved | non-reserved | reserved |
| LOCATION | non-reserved | non-reserved | non-reserved |
| LOCK | non-reserved | non-reserved | non-reserved |
| LOCKS | non-reserved | non-reserved | non-reserved |
| LOGICAL | non-reserved | non-reserved | non-reserved |
| LONG | non-reserved | non-reserved | non-reserved |
| LOOP | non-reserved | non-reserved | non-reserved |
| MACRO | non-reserved | non-reserved | non-reserved |
| MAP | non-reserved | non-reserved | non-reserved |
| MATCHED | non-reserved | non-reserved | non-reserved |
| MATERIALIZED | non-reserved | non-reserved | non-reserved |
| MAX | non-reserved | non-reserved | non-reserved |
| MEASURE | non-reserved | non-reserved | non-reserved |
| MERGE | non-reserved | non-reserved | non-reserved |
| METRICS | non-reserved | non-reserved | non-reserved |
| MICROSECOND | non-reserved | non-reserved | non-reserved |
| MICROSECONDS | non-reserved | non-reserved | non-reserved |
| MILLISECOND | non-reserved | non-reserved | non-reserved |
| MILLISECONDS | non-reserved | non-reserved | non-reserved |
| MINUTE | non-reserved | non-reserved | non-reserved |
| MINUTES | non-reserved | non-reserved | non-reserved |
| MINUS | non-reserved | strict-non-reserved | non-reserved |
| MODIFIES | non-reserved | non-reserved | non-reserved |
| MONTH | non-reserved | non-reserved | non-reserved |
| MONTHS | non-reserved | non-reserved | non-reserved |
| MSCK | non-reserved | non-reserved | non-reserved |
| NAME | non-reserved | non-reserved | non-reserved |
| NAMESPACE | non-reserved | non-reserved | non-reserved |
| NAMESPACES | non-reserved | non-reserved | non-reserved |
| NANOSECOND | non-reserved | non-reserved | non-reserved |
| NANOSECONDS | non-reserved | non-reserved | non-reserved |
| NATURAL | reserved | strict-non-reserved | reserved |
| NEAREST | non-reserved | non-reserved | non-reserved |
| NEXT | non-reserved | non-reserved | non-reserved |
| NO | non-reserved | non-reserved | reserved |
| NONE | non-reserved | non-reserved | reserved |
| NORELY | non-reserved | non-reserved | not a keyword |
| NOT | reserved | non-reserved | reserved |
| NULL | reserved | non-reserved | reserved |
| NULLS | non-reserved | non-reserved | non-reserved |
| NUMERIC | non-reserved | non-reserved | non-reserved |
| OF | non-reserved | non-reserved | reserved |
| OFFSET | reserved | non-reserved | reserved |
| ON | reserved | strict-non-reserved | reserved |
| ONLY | reserved | non-reserved | reserved |
| OPEN | non-reserved | non-reserved | reserved |
| OPTION | non-reserved | non-reserved | non-reserved |
| OPTIONS | non-reserved | non-reserved | non-reserved |
| OR | reserved | non-reserved | reserved |
| ORDER | reserved | non-reserved | reserved |
| OUT | non-reserved | non-reserved | reserved |
| OUTER | reserved | non-reserved | reserved |
| OUTPUTFORMAT | non-reserved | non-reserved | non-reserved |
| OVER | non-reserved | non-reserved | non-reserved |
| OVERLAPS | reserved | non-reserved | reserved |
| OVERLAY | non-reserved | non-reserved | non-reserved |
| OVERWRITE | non-reserved | non-reserved | non-reserved |
| PARTITION | non-reserved | non-reserved | reserved |
| PARTITIONED | non-reserved | non-reserved | non-reserved |
| PARTITIONS | non-reserved | non-reserved | non-reserved |
| PATH | non-reserved | non-reserved | not a keyword |
| PERCENT | non-reserved | non-reserved | non-reserved |
| PIVOT | non-reserved | non-reserved | non-reserved |
| PLACING | non-reserved | non-reserved | non-reserved |
| POSITION | non-reserved | non-reserved | reserved |
| PRECEDING | non-reserved | non-reserved | non-reserved |
| PRIMARY | reserved | non-reserved | reserved |
| PRINCIPALS | non-reserved | non-reserved | non-reserved |
| PROCEDURE | non-reserved | non-reserved | non-reserved |
| PROCEDURES | non-reserved | non-reserved | non-reserved |
| PROPERTIES | non-reserved | non-reserved | non-reserved |
| PURGE | non-reserved | non-reserved | non-reserved |
| QUALIFY | non-reserved | non-reserved | non-reserved |
| QUARTER | non-reserved | non-reserved | non-reserved |
| QUERY | non-reserved | non-reserved | non-reserved |
| RANGE | non-reserved | non-reserved | reserved |
| READ | non-reserved | non-reserved | non-reserved |
| READS | non-reserved | non-reserved | non-reserved |
| REAL | non-reserved | non-reserved | reserved |
| RECORDREADER | non-reserved | non-reserved | non-reserved |
| RECORDWRITER | non-reserved | non-reserved | non-reserved |
| RECOVER | non-reserved | non-reserved | non-reserved |
| RECURSION | non-reserved | non-reserved | non-reserved |
| RECURSIVE | reserved | non-reserved | reserved |
| REDUCE | non-reserved | non-reserved | non-reserved |
| REFERENCES | reserved | non-reserved | reserved |
| REFRESH | non-reserved | non-reserved | non-reserved |
| REGEXP | non-reserved | non-reserved | not a keyword |
| RELY | non-reserved | non-reserved | not a keyword |
| RENAME | non-reserved | non-reserved | non-reserved |
| REPAIR | non-reserved | non-reserved | non-reserved |
| REPEAT | non-reserved | non-reserved | non-reserved |
| REPEATABLE | non-reserved | non-reserved | non-reserved |
| REPLACE | non-reserved | non-reserved | non-reserved |
| RESET | non-reserved | non-reserved | non-reserved |
| RESPECT | non-reserved | non-reserved | non-reserved |
| RESTRICT | non-reserved | non-reserved | non-reserved |
| RETURN | non-reserved | non-reserved | reserved |
| RETURNS | non-reserved | non-reserved | reserved |
| REVOKE | non-reserved | non-reserved | reserved |
| RIGHT | reserved | strict-non-reserved | reserved |
| RLIKE | non-reserved | non-reserved | non-reserved |
| ROLE | non-reserved | non-reserved | non-reserved |
| ROLES | non-reserved | non-reserved | non-reserved |
| ROLLBACK | non-reserved | non-reserved | reserved |
| ROLLUP | non-reserved | non-reserved | reserved |
| ROW | non-reserved | non-reserved | reserved |
| ROWS | non-reserved | non-reserved | reserved |
| SCHEMA | non-reserved | non-reserved | non-reserved |
| SCHEMAS | non-reserved | non-reserved | non-reserved |
| SECOND | non-reserved | non-reserved | non-reserved |
| SECONDS | non-reserved | non-reserved | non-reserved |
| SECURITY | non-reserved | non-reserved | non-reserved |
| SELECT | reserved | non-reserved | reserved |
| SEMI | non-reserved | strict-non-reserved | non-reserved |
| SEPARATED | non-reserved | non-reserved | non-reserved |
| SERDE | non-reserved | non-reserved | non-reserved |
| SERDEPROPERTIES | non-reserved | non-reserved | non-reserved |
| SESSION_USER | reserved | non-reserved | reserved |
| SET | non-reserved | non-reserved | reserved |
| SETS | non-reserved | non-reserved | non-reserved |
| SHORT | non-reserved | non-reserved | non-reserved |
| SHOW | non-reserved | non-reserved | non-reserved |
| SIMILARITY | non-reserved | non-reserved | non-reserved |
| SINGLE | non-reserved | non-reserved | non-reserved |
| SKEWED | non-reserved | non-reserved | non-reserved |
| SMALLINT | non-reserved | non-reserved | reserved |
| SOME | reserved | non-reserved | reserved |
| SORT | non-reserved | non-reserved | non-reserved |
| SORTED | non-reserved | non-reserved | non-reserved |
| SOURCE | non-reserved | non-reserved | non-reserved |
| SPECIFIC | non-reserved | non-reserved | reserved |
| SQL | reserved | non-reserved | reserved |
| SQLEXCEPTION | non-reserved | non-reserved | non-reserved |
| SQLSTATE | non-reserved | non-reserved | non-reserved |
| START | non-reserved | non-reserved | reserved |
| STATISTICS | non-reserved | non-reserved | non-reserved |
| STORED | non-reserved | non-reserved | non-reserved |
| STRATIFY | non-reserved | non-reserved | non-reserved |
| STREAM | non-reserved | non-reserved | non-reserved |
| STREAMING | non-reserved | non-reserved | non-reserved |
| STRING | non-reserved | non-reserved | non-reserved |
| STRUCT | non-reserved | non-reserved | non-reserved |
| SUBSTR | non-reserved | non-reserved | non-reserved |
| SUBSTRING | non-reserved | non-reserved | non-reserved |
| SYNC | non-reserved | non-reserved | non-reserved |
| SYSTEM | non-reserved | non-reserved | reserved |
| SYSTEM_PATH | non-reserved | non-reserved | not a keyword |
| SYSTEM_TIME | non-reserved | non-reserved | non-reserved |
| SYSTEM_VERSION | non-reserved | non-reserved | non-reserved |
| TABLE | reserved | non-reserved | reserved |
| TABLES | non-reserved | non-reserved | non-reserved |
| TABLESAMPLE | non-reserved | non-reserved | reserved |
| TARGET | non-reserved | non-reserved | non-reserved |
| TBLPROPERTIES | non-reserved | non-reserved | non-reserved |
| TEMP | non-reserved | non-reserved | not a keyword |
| TEMPORARY | non-reserved | non-reserved | non-reserved |
| TERMINATED | non-reserved | non-reserved | non-reserved |
| THEN | reserved | non-reserved | reserved |
| TIME | reserved | non-reserved | reserved |
| TIMEDIFF | non-reserved | non-reserved | non-reserved |
| TIMESTAMP | non-reserved | non-reserved | non-reserved |
| TIMESTAMP_LTZ | non-reserved | non-reserved | non-reserved |
| TIMESTAMP_NTZ | non-reserved | non-reserved | non-reserved |
| TIMESTAMPADD | non-reserved | non-reserved | non-reserved |
| TIMESTAMPDIFF | non-reserved | non-reserved | non-reserved |
| TINYINT | non-reserved | non-reserved | non-reserved |
| TO | reserved | non-reserved | reserved |
| TOUCH | non-reserved | non-reserved | non-reserved |
| TRAILING | reserved | non-reserved | reserved |
| TRANSACTION | non-reserved | non-reserved | non-reserved |
| TRANSACTIONS | non-reserved | non-reserved | non-reserved |
| TRANSFORM | non-reserved | non-reserved | non-reserved |
| TRIM | non-reserved | non-reserved | non-reserved |
| TRUE | non-reserved | non-reserved | reserved |
| TRUNCATE | non-reserved | non-reserved | reserved |
| TRY_CAST | non-reserved | non-reserved | non-reserved |
| TYPE | non-reserved | non-reserved | non-reserved |
| UNARCHIVE | non-reserved | non-reserved | non-reserved |
| UNBOUNDED | non-reserved | non-reserved | non-reserved |
| UNCACHE | non-reserved | non-reserved | non-reserved |
| UNION | reserved | strict-non-reserved | reserved |
| UNIQUE | reserved | non-reserved | reserved |
| UNKNOWN | reserved | non-reserved | reserved |
| UNLOCK | non-reserved | non-reserved | non-reserved |
| UNPIVOT | non-reserved | non-reserved | non-reserved |
| UNSET | non-reserved | non-reserved | non-reserved |
| UNTIL | non-reserved | non-reserved | non-reserved |
| UPDATE | non-reserved | non-reserved | reserved |
| USE | non-reserved | non-reserved | non-reserved |
| USER | reserved | non-reserved | reserved |
| USING | reserved | strict-non-reserved | reserved |
| VALUE | non-reserved | non-reserved | non-reserved |
| VALUES | non-reserved | non-reserved | reserved |
| VARCHAR | non-reserved | non-reserved | reserved |
| VAR | non-reserved | non-reserved | non-reserved |
| VARIABLE | non-reserved | non-reserved | non-reserved |
| VARIANT | non-reserved | non-reserved | reserved |
| VERSION | non-reserved | non-reserved | non-reserved |
| VIEW | non-reserved | non-reserved | non-reserved |
| VIEWS | non-reserved | non-reserved | non-reserved |
| VOID | non-reserved | non-reserved | non-reserved |
| WATERMARK | non-reserved | non-reserved | non-reserved |
| WEEK | non-reserved | non-reserved | non-reserved |
| WEEKS | non-reserved | non-reserved | non-reserved |
| WHEN | reserved | non-reserved | reserved |
| WHERE | reserved | non-reserved | reserved |
| WHILE | non-reserved | non-reserved | non-reserved |
| WINDOW | non-reserved | non-reserved | reserved |
| WITH | reserved | non-reserved | reserved |
| WITHIN | reserved | non-reserved | reserved |
| WITHOUT | non-reserved | non-reserved | non-reserved |
| X | non-reserved | non-reserved | non-reserved |
| YEAR | non-reserved | non-reserved | non-reserved |
| YEARS | non-reserved | non-reserved | non-reserved |
| ZONE | non-reserved | non-reserved | non-reserved |
더 알아보기 (Learn more)
- 아파치 스파크 SQL 참조 (원문)
- Data Types — Spark SQL의 데이터 타입
- Datetime Pattern — 날짜/시간 패턴
- Built-in Functions — 내장 함수 목록