Массив перечислений введите в ClickHouse

#sql #arrays #enums #clickhouse

Вопрос:

В ClickHouse 21.4 я создал таблицу с массивом столбцов перечислений:

 CREATE TABLE test_array_enum (
    id String,
    fixation_at DateTime64(3, 'UTC'),
    types Array(
        Enum(
            'FIRST_TYPE' = 1, 'SECOND_TYPE' = 2, 'THIRD_TYPE' = 3,
            'FOURTH_TYPE' = 4
        )
    )
)
ENGINE = ReplacingMergeTree
ORDER BY (fixation_at, id);
 

Заполните некоторые данные:

 INSERT INTO test_array_enum (id, fixation_at, types) VALUES ('1', now64(), []),
                                                            ('2', now64(), ['FIRST_TYPE']),
                                                            ('3', now64(), ['SECOND_TYPE', 'THIRD_TYPE']),
                                                            ('4', now64(), ['FOURTH_TYPE']);
 

Я хочу отфильтровать данные по столбцам типов, запрос возвращает 0 строк:

 SELECT *
FROM test_array_enum
WHERE hasAny(types, ['SECOND_TYPE', 'THIRD_TYPE']);
 

Он отлично работает со значениями Int:

 SELECT *
FROM test_array_enum
WHERE hasAny(types, [2, 3]);
 

Есть ли способ фильтровать данные по строковым значениям перечисления?

Ответ №1:

Попробуйте выполнить этот запрос:

 SELECT *
FROM test_array_enum
WHERE arrayFirstIndex(x -> x = 'SECOND_TYPE' OR x = 'THIRD_TYPE', types) > 0

/*
┌─id─┬─────────────fixation_at─┬─types────────────────────────┐
│ 3  │ 2021-07-08 02:11:21.238 │ ['SECOND_TYPE','THIRD_TYPE'] │
└────┴─────────────────────────┴──────────────────────────────┘
*/
 

Комментарии:

1. Да, это работает идеально. На самом деле OR может быть заменен на IN : WHERE arrayFirstIndex(x -> x IN ('SECOND_TYPE', 'THIRD_TYPE'), types) > 0 . Я думаю, что более предпочтительно генерировать это условие с помощью кода.

Ответ №2:

Вы можете использовать приведение, если в этом есть смысл

 SELECT *
FROM test_array_enum
WHERE hasAny(types, CAST(['SECOND_TYPE', 'THIRD_TYPE'], 'Array(Enum('FIRST_TYPE' = 1, 'SECOND_TYPE' = 2, 'THIRD_TYPE' = 3, 'FOURTH_TYPE' = 4))'))
 

Комментарии:

1. Да, но мне все равно нужно сохранить сопоставление между значениями string и int в коде.