在Snowflake中,数组列中是否包含值?

huangapple go评论58阅读模式
英文:

Is value in array column in Snowflake?

问题

我需要生成一个布尔列,判断一个值(例如 1)是否在数组(例如 [1,2])中,针对表中的每一行。我的问题是:这样做的最佳方式是什么?

据我了解,在Snowflake中,ARRAY中的所有元素都是VARIANT类型。这展示了我正在使用的选项。我个人正在尝试弄清楚如何判断NUMBER列中的值是否是ARRAY列的元素。

示例

WITH example_cte AS (
    SELECT
        CAST(1 AS VARIANT) one_as_variant,
        CAST('1' AS VARIANT) string_one_as_variant,
        CAST(CAST(1 AS VARCHAR) AS VARIANT) as one_as_varchar_then_variant,
        [ '2', '1' ] AS my_array
)
SELECT
    ARRAY_CONTAINS(one_as_variant, my_array) as one_as_variant_is_in_array, -- evaluates as FALSE
    ARRAY_CONTAINS(string_one_as_variant, my_array) as string_one_as_variant_is_in_array, -- evaluates as TRUE
    ARRAY_CONTAINS(one_as_varchar_then_variant, my_array) as one_as_varchar_then_variant_is_in_array -- evaluates as TRUE
FROM
    example_cte;
英文:

I need to generate a boolean column that evaluates whether a value (e.g. 1) is in an array (e.g. [1,2]) for each row of my table. My question is: what is the best way to do this?

As I understand, all elements of an ARRAY in Snowflake are of type VARIANT. These demonstrate the options I'm working with. I'm personally trying to figure out how to see if the value in a NUMBER column is an element of the ARRAY column.

Example

WITH example_cte AS (
    SELECT
        CAST(1 AS VARIANT) one_as_variant,
        CAST('1' AS VARIANT) string_one_as_variant,
        CAST(CAST(1 AS VARCHAR) AS VARIANT) as one_as_varchar_then_variant,
        [ '2', '1' ] AS my_array
)
SELECT
    ARRAY_CONTAINS(one_as_variant, my_array) as one_as_variant_is_in_array, -- evaluates as FALSE
    ARRAY_CONTAINS(string_one_as_variant, my_array) as string_one_as_variant_is_in_array, -- evaluates as TRUE
    ARRAY_CONTAINS(one_as_varchar_then_variant, my_array) as one_as_varchar_then_variant_is_in_array -- evaluates as TRUE
FROM
    example_cte;

答案1

得分: 1

所以变体"have a type",因此字符串不是数字,如果尝试创建一个包含字符串的数字数组,则会失败,但数字数组则不会:

V1_N V1_S V1_N_S A1 A2 A1_CONTAINS_V1_N A1_CONTAINS_V1_S A1_CONTAINS_V1_N_S A2_CONTAINS_V1_N A2_CONTAINS_V1_S A2_CONTAINS_V1_N_S
1 "1" "1" [ "2", "1" ] [ 2, 1 ] FALSE TRUE TRUE TRUE FALSE FALSE

所以如果我们问类型是什么:

col value type
V1_N 1 INTEGER
V1_S "1" VARCHAR
V1_N_S "1" VARCHAR
A1 [ "2", "1" ] VARCHAR
A2 [ 2, 1 ] INTEGER

那么如何解决这个问题?

如果您的数组具有混合类型,您将不得不重建它们,但然后您就可以知道将值转换为什么类型。

或者,如果您知道数组的类型始终是字符串,就像您的示例一样,您可以只转换这些值:

V1_N V1_S V1_N_S A1 C_V1_N C_V1_S C_V1_N_S
1 "1" "1" [ "2", "1" ] TRUE TRUE TRUE
英文:

So the variant "have a type", and thus string are not number, and making an array of numbers, fails for the strings, but passes for the numbers:

SELECT
    1::VARIANT as v1_n,
    '1'::VARIANT as v1_s,
    1::VARCHAR::VARIANT as v1_n_s,
    array_construct('2', '1') as a1,
    array_construct(2, 1) as a2,
    ARRAY_CONTAINS(v1_n, a1) as a1_contains_v1_n,
    ARRAY_CONTAINS(v1_s, a1) as a1_contains_v1_s,
    ARRAY_CONTAINS(v1_n_s, a1) as a1_contains_v1_n_s,
    ARRAY_CONTAINS(v1_n, a2) as a2_contains_v1_n,
    ARRAY_CONTAINS(v1_s, a2) as a2_contains_v1_s,
    ARRAY_CONTAINS(v1_n_s, a2) as a2_contains_v1_n_s
V1_N V1_S V1_N_S A1 A2 A1_CONTAINS_V1_N A1_CONTAINS_V1_S A1_CONTAINS_V1_N_S A2_CONTAINS_V1_N A2_CONTAINS_V1_S A2_CONTAINS_V1_N_S
1 "1" "1" [ "2", "1" ] [ 2, 1 ] FALSE TRUE TRUE TRUE FALSE FALSE

so then if we ask what the types are:

SELECT
    1::VARIANT as v1_n,
    TYPEOF(v1_n) as t_v1_n,
    '1'::VARIANT as v1_s,
    TYPEOF(v1_s) as t_v1_s,
    1::VARCHAR::VARIANT as v1_n_s,
    TYPEOF(v1_n_s) as t_v1_n_s,
    array_construct('2', '1') as a1,
    TYPEOF(a1[0]) as t_a1_0,
    array_construct(2, 1) as a2,
    TYPEOF(a2[0]) as t_a2_0
col value type
V1_N 1 INTEGER
V1_S "1" VARCHAR
V1_N_S "1" VARCHAR
A1 [ "2", "1" ] VARCHAR
A2 [ 2, 1 ] INTEGER

so how to get around this?

If you array have mixed types, you will have to rebuild them, but then you can know what to cast your values to.

OR if you know the type of array is always strings, like in your example, you can just cast the values:

SELECT
    1::VARIANT as v1_n,
    '1'::VARIANT as v1_s,
    1::VARCHAR::VARIANT as v1_n_s,
    array_construct('2', '1') as a1,
    array_contains(v1_n::text::variant, a1) as c_v1_n,    
    array_contains(v1_s::text::variant, a1) as c_v1_s,   
    array_contains(v1_n_s::text::variant, a1) as c_v1_n_s
V1_N V1_S V1_N_S A1 C_V1_N C_V1_S C_V1_N_S
1 "1" "1" [ "2", "1" ] TRUE TRUE TRUE

huangapple
  • 本文由 发表于 2023年4月20日 04:28:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76058579.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定