메인 콘텐츠로 건너뛰기
이 타입은 다른 데이터 타입의 유니언을 나타냅니다. Variant(T1, T2, ..., TN) 타입은 이 타입의 각 행이 T1, T2, …, TN 중 하나의 타입 값을 가지거나, 어느 타입에도 해당하지 않는 NULL 값을 가질 수 있음을 의미합니다. 중첩된 타입의 순서는 중요하지 않습니다. 즉, Variant(T1, T2) = Variant(T2, T1)입니다. 중첩된 타입은 Nullable(…), LowCardinality(Nullable(…)), Variant(…) 타입을 제외하면 어떤 타입이든 사용할 수 있습니다.
유사한 타입을 variant로 사용하는 것은 권장되지 않습니다(예: Variant(UInt32, Int64)처럼 서로 다른 숫자 타입이나 Variant(Date, DateTime)처럼 서로 다른 날짜 타입). 이러한 타입의 값을 처리할 때 모호성이 발생할 수 있기 때문입니다. 기본적으로 이런 Variant 타입을 생성하면 예외가 발생하지만, 설정 allow_suspicious_variant_types를 사용해 활성화할 수 있습니다.

Variant 생성하기

테이블 컬럼 정의에서 Variant 타입을 사용하는 방법:
CREATE TABLE test (v Variant(UInt64, String, Array(UInt64))) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('Hello, World!'), ([1, 2, 3]);
SELECT v FROM test;
┌─v─────────────┐
│ ᴺᵁᴸᴸ          │
│ 42            │
│ Hello, World! │
│ [1,2,3]       │
└───────────────┘
일반 컬럼에서 CAST 사용:
SELECT toTypeName(variant) AS type_name, 'Hello, World!'::Variant(UInt64, String, Array(UInt64)) as variant;
┌─type_name──────────────────────────────┬─variant───────┐
│ Variant(Array(UInt64), String, UInt64) │ Hello, World! │
└────────────────────────────────────────┴───────────────┘
인수에 공통 타입이 없을 때 if/multiIf 함수를 사용합니다(use_variant_as_common_type 설정이 활성화되어 있어야 함):
SET use_variant_as_common_type = 1;
SELECT if(number % 2, number, range(number)) as variant FROM numbers(5);
┌─variant───┐
│ []        │
│ 1         │
│ [0,1]     │
│ 3         │
│ [0,1,2,3] │
└───────────┘
SET use_variant_as_common_type = 1;
SELECT multiIf((number % 4) = 0, 42, (number % 4) = 1, [1, 2, 3], (number % 4) = 2, 'Hello, World!', NULL) AS variant FROM numbers(4);
┌─variant───────┐
│ 42            │
│ [1,2,3]       │
│ Hello, World! │
│ ᴺᵁᴸᴸ          │
└───────────────┘
배열 요소/맵 값에 공통 타입이 없는 경우 ‘array/map’ 함수를 사용합니다(이 기능을 사용하려면 use_variant_as_common_type 설정이 활성화되어 있어야 합니다):
SET use_variant_as_common_type = 1;
SELECT array(range(number), number, 'str_' || toString(number)) as array_of_variants FROM numbers(3);
┌─array_of_variants─┐
│ [[],0,'str_0']    │
│ [[0],1,'str_1']   │
│ [[0,1],2,'str_2'] │
└───────────────────┘
SET use_variant_as_common_type = 1;
SELECT map('a', range(number), 'b', number, 'c', 'str_' || toString(number)) as map_of_variants FROM numbers(3);
┌─map_of_variants───────────────┐
│ {'a':[],'b':0,'c':'str_0'}    │
│ {'a':[0],'b':1,'c':'str_1'}   │
│ {'a':[0,1],'b':2,'c':'str_2'} │
└───────────────────────────────┘

Variant 중첩 타입을 서브컬럼으로 읽기

Variant 타입은 타입 이름을 서브컬럼으로 사용해 Variant 컬럼에서 특정 중첩 타입 하나를 읽을 수 있도록 지원합니다. 따라서 variant Variant(T1, T2, T3) 컬럼이 있으면 variant.T2 구문을 사용해 T2 타입의 서브컬럼을 읽을 수 있습니다. 이 서브컬럼의 타입은 T2Nullable 안에 포함될 수 있으면 Nullable(T2)이고, 그렇지 않으면 T2입니다. 또한 이 서브컬럼은 원래 Variant 컬럼과 동일한 크기를 가지며, 원래 Variant 컬럼의 타입이 T2가 아닌 모든 행에는 NULL 값(T2Nullable 안에 포함될 수 없으면 빈 값)이 들어갑니다. Variant 서브컬럼은 variantElement(variant_column, type_name) 함수를 사용해서도 읽을 수 있습니다. 예시:
CREATE TABLE test (v Variant(UInt64, String, Array(UInt64))) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('Hello, World!'), ([1, 2, 3]);
SELECT v, v.String, v.UInt64, v.`Array(UInt64)` FROM test;
┌─v─────────────┬─v.String──────┬─v.UInt64─┬─v.Array(UInt64)─┐
│ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ          │     ᴺᵁᴸᴸ │ []              │
│ 42            │ ᴺᵁᴸᴸ          │       42 │ []              │
│ Hello, World! │ Hello, World! │     ᴺᵁᴸᴸ │ []              │
│ [1,2,3]       │ ᴺᵁᴸᴸ          │     ᴺᵁᴸᴸ │ [1,2,3]         │
└───────────────┴───────────────┴──────────┴─────────────────┘
SELECT toTypeName(v.String), toTypeName(v.UInt64), toTypeName(v.`Array(UInt64)`) FROM test LIMIT 1;
┌─toTypeName(v.String)─┬─toTypeName(v.UInt64)─┬─toTypeName(v.Array(UInt64))─┐
│ Nullable(String)     │ Nullable(UInt64)     │ Array(UInt64)               │
└──────────────────────┴──────────────────────┴─────────────────────────────┘
SELECT v, variantElement(v, 'String'), variantElement(v, 'UInt64'), variantElement(v, 'Array(UInt64)') FROM test;
┌─v─────────────┬─variantElement(v, 'String')─┬─variantElement(v, 'UInt64')─┬─variantElement(v, 'Array(UInt64)')─┐
│ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ                        │                        ᴺᵁᴸᴸ │ []                                 │
│ 42            │ ᴺᵁᴸᴸ                        │                          42 │ []                                 │
│ Hello, World! │ Hello, World!               │                        ᴺᵁᴸᴸ │ []                                 │
│ [1,2,3]       │ ᴺᵁᴸᴸ                        │                        ᴺᵁᴸᴸ │ [1,2,3]                            │
└───────────────┴─────────────────────────────┴─────────────────────────────┴────────────────────────────────────┘
각 행에 저장된 variant를 확인하려면 variantType(variant_column) 함수를 사용할 수 있습니다. 이 함수는 각 행의 variant 유형 이름을 나타내는 Enum을 반환합니다(NULL인 행은 'None'). 예시:
CREATE TABLE test (v Variant(UInt64, String, Array(UInt64))) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('Hello, World!'), ([1, 2, 3]);
SELECT variantType(v) FROM test;
┌─variantType(v)─┐
│ None           │
│ UInt64         │
│ String         │
│ Array(UInt64)  │
└────────────────┘
SELECT toTypeName(variantType(v)) FROM test LIMIT 1;
┌─toTypeName(variantType(v))──────────────────────────────────────────┐
│ Enum8('None' = -1, 'Array(UInt64)' = 0, 'String' = 1, 'UInt64' = 2) │
└─────────────────────────────────────────────────────────────────────┘

Variant 컬럼과 다른 컬럼 사이의 변환

Variant 타입의 컬럼에 대해 수행할 수 있는 변환은 4가지입니다.

String 컬럼을 Variant 컬럼으로 변환하기

String에서 Variant로의 변환은 문자열 값을 파싱해 Variant 타입의 값을 추출하는 방식으로 수행됩니다:
SELECT '42'::Variant(String, UInt64) AS variant, variantType(variant) AS variant_type
┌─variant─┬─variant_type─┐
│ 42      │ UInt64       │
└─────────┴──────────────┘
SELECT '[1, 2, 3]'::Variant(String, Array(UInt64)) as variant, variantType(variant) as variant_type
┌─variant─┬─variant_type──┐
│ [1,2,3] │ Array(UInt64) │
└─────────┴───────────────┘
SELECT CAST(map('key1', '42', 'key2', 'true', 'key3', '2020-01-01'), 'Map(String, Variant(UInt64, Bool, Date))') AS map_of_variants, mapApply((k, v) -> (k, variantType(v)), map_of_variants) AS map_of_variant_types```
┌─map_of_variants─────────────────────────────┬─map_of_variant_types──────────────────────────┐
│ {'key1':42,'key2':true,'key3':'2020-01-01'} │ {'key1':'UInt64','key2':'Bool','key3':'Date'} │
└─────────────────────────────────────────────┴───────────────────────────────────────────────┘
String에서 Variant로 변환할 때 파싱을 비활성화하려면 cast_string_to_dynamic_use_inference 설정을 비활성화하면 됩니다:
SET cast_string_to_variant_use_inference = 0;
SELECT '[1, 2, 3]'::Variant(String, Array(UInt64)) as variant, variantType(variant) as variant_type
┌─variant───┬─variant_type─┐
│ [1, 2, 3] │ String       │
└───────────┴──────────────┘

일반 컬럼을 Variant 컬럼으로 변환하기

타입이 T인 일반 컬럼은 해당 타입을 포함하는 Variant 컬럼으로 변환할 수 있습니다:
SELECT toTypeName(variant) AS type_name, [1,2,3]::Array(UInt64)::Variant(UInt64, String, Array(UInt64)) as variant, variantType(variant) as variant_name
┌─type_name──────────────────────────────┬─variant─┬─variant_name──┐
│ Variant(Array(UInt64), String, UInt64) │ [1,2,3] │ Array(UInt64) │
└────────────────────────────────────────┴─────────┴───────────────┘
참고: String 타입에서의 변환은 항상 파싱을 거쳐 수행됩니다. 파싱 없이 String 컬럼을 VariantString 대안으로 변환해야 하는 경우, 다음과 같이 할 수 있습니다:
SELECT '[1, 2, 3]'::Variant(String)::Variant(String, Array(UInt64), UInt64) as variant, variantType(variant) as variant_type
┌─variant───┬─variant_type─┐
│ [1, 2, 3] │ String       │
└───────────┴──────────────┘

Variant 컬럼을 일반 컬럼으로 변환하기

Variant 컬럼은 일반 컬럼으로 변환할 수 있습니다. 이 경우 모든 중첩된 variant가 대상 타입으로 변환됩니다:
CREATE TABLE test (v Variant(UInt64, String)) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('42.42');
SELECT v::Nullable(Float64) FROM test;
┌─CAST(v, 'Nullable(Float64)')─┐
│                         ᴺᵁᴸᴸ │
│                           42 │
│                        42.42 │
└──────────────────────────────┘

Variant를 다른 Variant로 변환하기

Variant 컬럼은 다른 Variant 컬럼으로 변환할 수 있지만, 대상 Variant 컬럼에 원래 Variant의 모든 중첩 타입이 포함된 경우에만 가능합니다:
CREATE TABLE test (v Variant(UInt64, String)) ENGINE = Memory;
INSERT INTO test VALUES (NULL), (42), ('String');
SELECT v::Variant(UInt64, String, Array(UInt64)) FROM test;
┌─CAST(v, 'Variant(UInt64, String, Array(UInt64))')─┐
│ ᴺᵁᴸᴸ                                              │
│ 42                                                │
│ String                                            │
└───────────────────────────────────────────────────┘

데이터에서 Variant 타입 읽기

모든 텍스트 형식(TSV, CSV, CustomSeparated, Values, JSONEachRow 등)에서 Variant 타입을 읽을 수 있습니다. 데이터를 파싱하는 동안 ClickHouse는 값을 가장 적합한 Variant 타입으로 삽입하려고 시도합니다. 예시:
SELECT
    v,
    variantElement(v, 'String') AS str,
    variantElement(v, 'UInt64') AS num,
    variantElement(v, 'Float64') AS float,
    variantElement(v, 'DateTime') AS date,
    variantElement(v, 'Array(UInt64)') AS arr
FROM format(JSONEachRow, 'v Variant(String, UInt64, Float64, DateTime, Array(UInt64))', $$
{"v" : "Hello, World!"},
{"v" : 42},
{"v" : 42.42},
{"v" : "2020-01-01 00:00:00"},
{"v" : [1, 2, 3]}
$$)
┌─v───────────────────┬─str───────────┬──num─┬─float─┬────────────────date─┬─arr─────┐
│ Hello, World!       │ Hello, World! │ ᴺᵁᴸᴸ │  ᴺᵁᴸᴸ │                ᴺᵁᴸᴸ │ []      │
│ 42                  │ ᴺᵁᴸᴸ          │   42 │  ᴺᵁᴸᴸ │                ᴺᵁᴸᴸ │ []      │
│ 42.42               │ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ │ 42.42 │                ᴺᵁᴸᴸ │ []      │
│ 2020-01-01 00:00:00 │ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ │  ᴺᵁᴸᴸ │ 2020-01-01 00:00:00 │ []      │
│ [1,2,3]             │ ᴺᵁᴸᴸ          │ ᴺᵁᴸᴸ │  ᴺᵁᴸᴸ │                ᴺᵁᴸᴸ │ [1,2,3] │
└─────────────────────┴───────────────┴──────┴───────┴─────────────────────┴─────────┘

Variant 타입 값 비교

Variant 타입의 값은 동일한 Variant 타입의 값과만 비교할 수 있습니다. 기본적으로 비교 연산자는 Variant의 기본 구현을 사용하여 각 variant type에 대해 개별적으로 비교를 수행합니다. 이는 setting use_variant_default_implementation_for_comparisons = 0을 사용해 비활성화할 수 있으며, 이 경우 아래에 설명된 네이티브 Variant 비교 규칙이 사용됩니다. 참고: ORDER BY는 항상 네이티브 비교를 사용합니다. 네이티브 Variant 비교 규칙: 타입 Variant(..., T1, ... T2, ...)에서 내부 타입이 T1인 값 v1과 내부 타입이 T2인 값 v2에 대한 연산자 <의 결과는 다음과 같이 정의됩니다.
  • T1 = T2 = T이면 결과는 v1.T < v2.T입니다(내부 값이 비교됩니다).
  • T1 != T2이면 결과는 T1 < T2입니다(타입 이름이 비교됩니다).
예시:
SET allow_suspicious_types_in_order_by = 1;
CREATE TABLE test (v1 Variant(String, UInt64, Array(UInt32)), v2 Variant(String, UInt64, Array(UInt32))) ENGINE=Memory;
INSERT INTO test VALUES (42, 42), (42, 43), (42, 'abc'), (42, [1, 2, 3]), (42, []), (42, NULL);
SELECT v2, variantType(v2) AS v2_type FROM test ORDER BY v2;
┌─v2──────┬─v2_type───────┐
│ []      │ Array(UInt32) │
│ [1,2,3] │ Array(UInt32) │
│ abc     │ String        │
│ 42      │ UInt64        │
│ 43      │ UInt64        │
│ ᴺᵁᴸᴸ    │ None          │
└─────────┴───────────────┘
SELECT v1, variantType(v1) AS v1_type, v2, variantType(v2) AS v2_type, v1 = v2, v1 < v2, v1 > v2 FROM test;
┌─v1─┬─v1_type─┬─v2──────┬─v2_type───────┬─equals(v1, v2)─┬─less(v1, v2)─┬─greater(v1, v2)─┐
│ 42 │ UInt64  │ 42      │ UInt64        │              1 │            0 │               0 │
│ 42 │ UInt64  │ 43      │ UInt64        │              0 │            1 │               0 │
│ 42 │ UInt64  │ abc     │ String        │              0 │            0 │               1 │
│ 42 │ UInt64  │ [1,2,3] │ Array(UInt32) │              0 │            0 │               1 │
│ 42 │ UInt64  │ []      │ Array(UInt32) │              0 │            0 │               1 │
│ 42 │ UInt64  │ ᴺᵁᴸᴸ    │ None          │              0 │            1 │               0 │
└────┴─────────┴─────────┴───────────────┴────────────────┴──────────────┴─────────────────┘

특정 Variant 값을 가진 행을 찾아야 한다면, 다음 방법 중 하나를 사용할 수 있습니다:
  • 값을 해당 Variant 유형으로 CAST합니다:
SELECT * FROM test WHERE v2 == [1,2,3]::Array(UInt32)::Variant(String, UInt64, Array(UInt32));
┌─v1─┬─v2──────┐
│ 42 │ [1,2,3] │
└────┴─────────┘
  • Variant 서브컬럼을 필요한 타입과 비교합니다:
SELECT * FROM test WHERE v2.`Array(UInt32)` == [1,2,3] -- 또는 variantElement(v2, 'Array(UInt32)') 사용
┌─v1─┬─v2──────┐
│ 42 │ [1,2,3] │
└────┴─────────┘
Array/Map/Tuple 같은 복합 타입의 서브컬럼은 Nullable 안에 포함될 수 없으며, 타입이 다른 행에서는 NULL 대신 기본값을 가지므로, 경우에 따라 variant 타입에 추가 검사를 수행하는 것이 유용할 수 있습니다:
SELECT v2, v2.`Array(UInt32)`, variantType(v2) FROM test WHERE v2.`Array(UInt32)` == [];
┌─v2───┬─v2.Array(UInt32)─┬─variantType(v2)─┐
│ 42   │ []               │ UInt64          │
│ 43   │ []               │ UInt64          │
│ abc  │ []               │ String          │
│ []   │ []               │ Array(UInt32)   │
│ ᴺᵁᴸᴸ │ []               │ None            │
└──────┴──────────────────┴─────────────────┘
SELECT v2, v2.`Array(UInt32)`, variantType(v2) FROM test WHERE variantType(v2) == 'Array(UInt32)' AND v2.`Array(UInt32)` == [];
┌─v2─┬─v2.Array(UInt32)─┬─variantType(v2)─┐
│ [] │ []               │ Array(UInt32)   │
└────┴──────────────────┴─────────────────┘
참고: 숫자 타입이 서로 다른 Variant 값은 서로 다른 Variant로 간주되며, 서로 비교하지 않고 대신 타입 이름을 비교합니다. 예시:
SET allow_suspicious_variant_types = 1;
CREATE TABLE test (v Variant(UInt32, Int64)) ENGINE=Memory;
INSERT INTO test VALUES (1::UInt32), (1::Int64), (100::UInt32), (100::Int64);
SELECT v, variantType(v) FROM test ORDER by v;
┌─v───┬─variantType(v)─┐
│ 1   │ Int64          │
│ 100 │ Int64          │
│ 1   │ UInt32         │
│ 100 │ UInt32         │
└─────┴────────────────┘
참고 기본적으로 Variant 타입은 GROUP BY/ORDER BY 키로 사용할 수 없습니다. 사용하려면 이 타입의 특수한 비교 규칙을 고려하고 allow_suspicious_types_in_group_by/allow_suspicious_types_in_order_by 설정을 활성화하십시오.

Variant를 지원하는 JSONExtract 함수

모든 JSONExtract* 함수는 Variant 타입을 지원합니다.
SELECT JSONExtract('{"a" : [1, 2, 3]}', 'a', 'Variant(UInt32, String, Array(UInt32))') AS variant, variantType(variant) AS variant_type;
┌─variant─┬─variant_type──┐
│ [1,2,3] │ Array(UInt32) │
└─────────┴───────────────┘
SELECT JSONExtract('{"obj" : {"a" : 42, "b" : "Hello", "c" : [1,2,3]}}', 'obj', 'Map(String, Variant(UInt32, String, Array(UInt32)))') AS map_of_variants, mapApply((k, v) -> (k, variantType(v)), map_of_variants) AS map_of_variant_types
┌─map_of_variants──────────────────┬─map_of_variant_types────────────────────────────┐
│ {'a':42,'b':'Hello','c':[1,2,3]} │ {'a':'UInt32','b':'String','c':'Array(UInt32)'} │
└──────────────────────────────────┴─────────────────────────────────────────────────┘
SELECT JSONExtractKeysAndValues('{"a" : 42, "b" : "Hello", "c" : [1,2,3]}', 'Variant(UInt32, String, Array(UInt32))') AS variants, arrayMap(x -> (x.1, variantType(x.2)), variants) AS variant_types
┌─variants───────────────────────────────┬─variant_types─────────────────────────────────────────┐
│ [('a',42),('b','Hello'),('c',[1,2,3])] │ [('a','UInt32'),('b','String'),('c','Array(UInt32)')] │
└────────────────────────────────────────┴───────────────────────────────────────────────────────┘

Variant 인수를 사용하는 함수

ClickHouse의 대부분의 함수는 Variant에 대한 기본 구현을 통해 Variant 타입 인수를 자동으로 지원합니다. 26.1 버전부터는 Variant 타입을 명시적으로 처리하지 않는 함수에 Variant 컬럼이 전달되면 ClickHouse는 다음을 수행합니다:
  1. Variant 컬럼에서 각 변형 타입을 추출합니다
  2. 각 변형 타입에 대해 함수를 개별적으로 실행합니다
  3. 결과 타입에 따라 결과를 적절히 결합합니다
따라서 별도의 특별한 처리 없이도 일반 함수를 Variant 컬럼에 사용할 수 있습니다. 예시:
CREATE TABLE test (v Variant(UInt32, String)) ENGINE = Memory;
INSERT INTO test VALUES (42), ('hello'), (NULL);
SELECT *, toTypeName(v) FROM test WHERE v = 42;
   ┌─v──┬─toTypeName(v)───────────┐
1. │ 42 │ Variant(String, UInt32) │
   └────┴─────────────────────────┘
비교 연산자는 각 variant 타입에 자동으로 개별 적용되므로 Variant 컬럼을 필터링할 수 있습니다. 결과 타입 동작: 결과 타입은 함수가 각 variant에 대해 반환하는 값에 따라 달라집니다.
  • 서로 다른 결과 타입: Variant(T1, T2, ...)
    CREATE TABLE test2 (v Variant(UInt64, Float64)) ENGINE = Memory;
    INSERT INTO test2 VALUES (42::UInt64), (42.42);
    SELECT v + 1 AS result, toTypeName(result) FROM test2;
    
    ┌─result─┬─toTypeName(plus(v, 1))──┐
    │     43 │ Variant(Float64, UInt64) │
    │  43.42 │ Variant(Float64, UInt64) │
    └────────┴─────────────────────────┘
    
  • 타입 비호환성: 호환되지 않는 variant에는 NULL
    CREATE TABLE test3 (v Variant(Array(UInt32), UInt32)) ENGINE = Memory;
    INSERT INTO test3 VALUES ([1,2,3]), (42);
    SELECT v + 10 AS result, toTypeName(result) FROM test3;
    
    ┌─result─┬─toTypeName(plus(v, 10))─┐
    │   ᴺᵁᴸᴸ │ Nullable(UInt64)        │
    │     52 │ Nullable(UInt64)        │
    └────────┴─────────────────────────┘
    
오류 처리: 함수가 variant 타입을 처리할 수 없을 때는 타입 관련 오류(ILLEGAL_TYPE_OF_ARGUMENT, TYPE_MISMATCH, CANNOT_CONVERT_TYPE, NO_COMMON_TYPE)만 포착되며, 해당 행의 결과는 NULL이 됩니다. 그 밖의 오류(예: 0으로 나누기, 메모리 부족)는 실제 문제를 조용히 숨기지 않도록 평소처럼 그대로 발생합니다.

유형 불일치 시 동작

설정 variant_throw_on_type_mismatch는 함수가 Variant 컬럼에 적용될 때, 행에 실제로 저장된 유형이 해당 함수와 호환되지 않으면 어떻게 처리할지를 제어합니다:
  • true (기본값) — 처음으로 호환되지 않는 행에서 예외(ILLEGAL_TYPE_OF_ARGUMENT)를 발생시킵니다.
  • false — 호환되지 않는 행에는 NULL을 반환하고, 호환되는 행은 결과를 유지합니다.
예시:
CREATE TABLE test (v Variant(String, UInt64)) ENGINE = Memory;
INSERT INTO test VALUES ('hello'), (42), ('foo');

-- 기본값 (불일치 시 예외 발생): length()는 UInt64를 허용하지 않으므로 쿼리에서 예외가 발생합니다.
SELECT length(v) FROM test;  -- ILLEGAL_TYPE_OF_ARGUMENT 예외 발생

-- throw 비활성화 시: 호환되지 않는 행은 NULL을 반환합니다.
SET variant_throw_on_type_mismatch = false;
SELECT v, length(v) FROM test ORDER BY v::String NULLS LAST;
┌─v─────┬─length(v)─┐
│ foo   │         3 │
│ hello │         5 │
│ 42    │      ᴺᵁᴸᴸ │
└───────┴───────────┘
마지막 수정일 2026년 6월 10일