Динамический выбор колонок является мощной, но недоиспользуемой функцией ClickHouse, которая позволяет выбирать колонки, используя регулярные выражения вместо того, чтобы называть каждую колонку по отдельности. Вы также можете применять функции к совпадающим колонкам с помощью модификатора APPLY, что делает его невероятно полезным для задач анализа и трансформации данных.
Начнем с распространенного сценария: выбор только тех колонок, которые содержат _amount из набора данных такси Нью-Йорка. Вместо того чтобы вручную набирать каждое имя колонки, мы можем использовать выражение COLUMNS с регулярным выражением:
FROM nyc_taxi.trips
SELECT COLUMNS('.*_amount')
LIMIT 10;
Этот запрос возвращает первые 10 строк, но только для колонок, чьи имена соответствуют шаблону .*_amount (любые символы, за которыми следует "_amount").
Мы также можем использовать модификатор APPLY для применения функций ко всем колонкам.
Например, если мы хотим найти максимальное значение каждой из этих колонок, мы можем выполнить следующий запрос:
SELECT COLUMNS('.*_amount|fee|tax') APPLY(max)
FROM nyc_taxi.trips;
Эти значения содержат много десятичных знаков, но, к счастью, мы можем это исправить, комбинируя функции. В этом случае мы применим функцию avg, за которой следует функция round:
SELECT COLUMNS('.*_amount|fee|tax') APPLY(avg) APPLY(round)
FROM nyc_taxi.trips;
Но это округляет средние значения до целых чисел. Если мы хотим округлить, скажем, до 2 десятичных знаков, мы можем сделать это также. Наряду с функциями, модификатор APPLY принимает лямбду, что дает нам гибкость сделать так, чтобы функция round округляла наши средние значения до 2 десятичных знаков:
SELECT COLUMNS('.*_amount|fee|tax') APPLY(avg) APPLY(x -> round(x, 2))
FROM nyc_taxi.trips;
Пока что всё хорошо. Но давайте представим, что мы хотим скорректировать одно из значений, оставив остальные без изменений. Например, возможно, мы хотим удвоить общую сумму и разделить налог MTA на 1.1. Мы можем сделать это, используя модификатор REPLACE, который заменяет колонку, оставляя остальные такими, какие они есть.
FROM nyc_taxi.trips
SELECT
COLUMNS('.*_amount|fee|tax')
REPLACE(
total_amount*2 AS total_amount,
mta_tax/1.1 AS mta_tax
)
APPLY(avg)
APPLY(col -> round(col, 2));