
本文字数:4073;估计阅读时间:11 分钟
审校:庄晓东(魏庄)
在处理包含大量列的数据集时,我们通常希望在其中的一部分列上做聚合计算。
如果,不得不手工键入所有要操作的列,那就会相当的繁琐,所以我很高兴地了解到:ClickHouse具有允许动态列选择的功能。


我们将使用NYC出租车数据集,特别是2023年1月的黄色出租车数据。我们将下载该月的Parquet文件,然后启动ClickHouse Local实例并将其导入:
./clickhouse local -m
CREATE TABLE trips ENGINE MergeTreeORDER BY (tpep_pickup_datetime) ASfrom file('yellow tripdata Jan 2023.parquet', Parquet)select *SETTINGS schema_inference_make_columns_nullable = 0;
DESCRIBE TABLE tripsSETTINGS describe_compact_output = 1;
┌─name──────────────────┬─type──────────┐│ VendorID │ Int64 ││ tpep_pickup_datetime │ DateTime64(6) ││ tpep_dropoff_datetime │ DateTime64(6) ││ passenger_count │ Float64 ││ trip_distance │ Float64 ││ RatecodeID │ Float64 ││ store_and_fwd_flag │ String ││ PULocationID │ Int64 ││ DOLocationID │ Int64 ││ payment_type │ Int64 ││ fare_amount │ Float64 ││ extra │ Float64 ││ mta_tax │ Float64 ││ tip_amount │ Float64 ││ tolls_amount │ Float64 ││ improvement_surcharge │ Float64 ││ total_amount │ Float64 ││ congestion_surcharge │ Float64 ││ airport_fee │ Float64 │└───────────────────────┴───────────────┘

现在,假设我们只想使用包含_amount的列。我们不必逐一的键入这些列,而是可以使用COLUMNS子句返回与正则表达式匹配所需要的列。查询返回前10行金额列的查询如下:
FROM tripsSELECT COLUMNS('.*_amount')LIMIT 10;
┌─fare_amount─┬─tip_amount─┬─tolls_amount─┬─total_amount─┐│ 0 │ 0 │ 0 │ 0 ││ 120 │ 0 │ 0 │ 120.3 ││ 45 │ 9.06 │ 0 │ 54.36 ││ 75 │ 15.06 │ 0 │ 90.36 ││ 55 │ 14.45 │ 0 │ 72.25 ││ 4.5 │ 0 │ 0 │ 6.55 ││ 10 │ 0 │ 0 │ 10.8 ││ 115 │ 5 │ 0 │ 120.3 ││ 78 │ 15.76 │ 0 │ 94.56 ││ 19.5 │ 0 │ 0 │ 21.55 │└─────────────┴────────────┴──────────────┴──────────────┘
FROM tripsSELECTCOLUMNS('.*_amount|fee|tax')ORDER BY rand()LIMIT 3FORMAT Vertical;
Row 1:──────fare_amount: 9.3mta_tax: 0.5tip_amount: 0tolls_amount: 0total_amount: 13.3airport_fee: 0Row 2:──────fare_amount: 10mta_tax: 0.5tip_amount: 2tolls_amount: 0total_amount: 16airport_fee: 0Row 3:──────fare_amount: 18.4mta_tax: 0.5tip_amount: 1tolls_amount: 0total_amount: 23.4airport_fee: 0

我们还可以使用APPLY函数在每列上应用函数。例如,如果我们想找到每列的最大值,我们可以运行以下查询:
FROM tripsSELECTCOLUMNS('.*_amount|fee|tax')APPLY(max)FORMAT Vertical;
Row 1:──────max(fare_amount): 1160.1max(mta_tax): 53.16max(tip_amount): 380.8max(tolls_amount): 196.99max(total_amount): 1169.4max(airport_fee): 1.25
FROM tripsSELECTCOLUMNS('.*_amount|fee|tax')APPLY(avg)FORMAT Vertical;
Row 1:──────avg(fare_amount): 18.36706861234277avg(mta_tax): 0.48828997712900174avg(tip_amount): 3.3679406710521764avg(tolls_amount): 0.5184906575852216avg(total_amount): 27.020383107155837avg(airport_fee): 0.10489592293640923
FROM tripsSELECTCOLUMNS('.*_amount|fee|tax')APPLY(avg)APPLY(round)FORMAT Vertical;
Row 1:──────round(avg(fare_amount)): 18round(avg(mta_tax)): 0round(avg(tip_amount)): 3round(avg(tolls_amount)): 1round(avg(total_amount)): 27round(avg(airport_fee)): 0
FROM tripsSELECTCOLUMNS('.*_amount|fee|tax')APPLY(avg)APPLY(col -> round(col, 2))FORMAT Vertical;
Row 1:──────round(avg(fare_amount), 2): 18.37round(avg(mta_tax), 2): 0.49round(avg(tip_amount), 2): 3.37round(avg(tolls_amount), 2): 0.52round(avg(total_amount), 2): 27.02round(avg(airport_fee), 2): 0.1

到目前为止一切顺利。但是,假设我们想调整一个值,同时将其他值保持不变。例如,也许我们想将总金额翻倍,并将MTA税除以1.1。我们可以使用REPLACE子句来实现此目的,该子句将替换一个列,同时将其他列保持不变。
FROM tripsSELECTCOLUMNS('.*_amount|fee|tax')REPLACE(total_amount*2 AS total_amount,mta_tax/1.1 AS mta_tax)APPLY(avg)APPLY(col -> round(col, 2))FORMAT Vertical;
Row 1:──────round(avg(fare_amount), 2): 18.37round(divide(avg(mta_tax), 1.1), 2): 0.44round(avg(tip_amount), 2): 3.37round(avg(tolls_amount), 2): 0.52round(multiply(avg(total_amount), 2), 2): 54.04round(avg(airport_fee), 2): 0.1
我们还可以选择使用EXCEPT子句排除一个字段。例如,要删除tolls_amount列,我们将编写以下查询:
FROM tripsSELECTCOLUMNS('.*_amount|fee|tax') EXCEPT(tolls_amount)REPLACE(total_amount*2 AS total_amount,mta_tax/1.1 AS mta_tax)APPLY(avg)APPLY(col -> round(col, 2))FORMAT Vertical;
Row 1:──────round(avg(fare_amount), 2): 18.37round(divide(avg(mta_tax), 1.1), 2): 0.44round(avg(tip_amount), 2): 3.37round(multiply(avg(total_amount), 2), 2): 54.04round(avg(airport_fee), 2): 0.1

希望您已经看到,即使是一个没有太多列的数据集,ClickHouse的动态列选择功能也能在SQL查询中节省大量输入。
在您自己的数据上尝试这些查询,然后告诉我们您的使用体验!


文章转载自ClickHouseInc,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




