ClickHouse通过CSV自动建表遇Nullable排序键问题及方案咨询
问题描述
我有一个CSV文件,希望导入ClickHouse时创建表并做转换(选择部分列、对部分数据应用函数),尝试执行以下语句:
CREATE TABLE test_csv ORDER BY some_csv_column AS SELECT some_csv_column, some_other_column FROM file('myuserfiles/mydata.csv.gz', 'CSVWithNames', 'auto', 'gzip')
但收到报错:
Code: 44. DB::Exception: Received from localhost:9000. DB::Exception: Sorting key contains nullable columns, but merge tree setting `allow_nullable_key` is disabled. (ILLEGAL_COLUMN)
推测用于ORDER BY的字段在自动生成的schema中为Nullable类型,而引擎不允许。现咨询三个问题:
- 能否在仍使用
auto的前提下,指定some_csv_column为非Nullable类型? - 如何临时启用
allow_nullable_key设置,之后再禁用(实际数据无空值,若存在则报错)? - 实现该需求的其他方法有哪些?
解答
1. 使用auto时指定列非Nullable类型
可以通过在SELECT语句里对目标列使用assumeNotNull()函数强制转换为非Nullable类型,同时保留auto自动推断其他列的逻辑:
CREATE TABLE test_csv ORDER BY some_csv_column AS SELECT assumeNotNull(some_csv_column) AS some_csv_column, some_other_column FROM file('myuserfiles/mydata.csv.gz', 'CSVWithNames', 'auto', 'gzip')
如果原数据中存在NULL值,assumeNotNull()会直接抛出异常,符合你“存在空值则报错”的需求。
2. 临时启用allow_nullable_key
会话级别临时生效
在执行建表语句前,先运行以下命令,该设置仅在当前会话内有效:
SET allow_nullable_key = 1;
完成建表后,关闭当前会话即可自动恢复默认配置;也可以手动执行SET allow_nullable_key = 0;主动禁用。
语句级别临时生效
直接在CREATE TABLE语句中通过SETTINGS子句指定该参数,仅对当前建表操作生效,不会影响全局或其他会话:
CREATE TABLE test_csv ORDER BY some_csv_column AS SELECT some_csv_column, some_other_column FROM file('myuserfiles/mydata.csv.gz', 'CSVWithNames', 'auto', 'gzip') SETTINGS allow_nullable_key = 1;
3. 其他实现方法
- 手动指定完整Schema:放弃
auto自动推断,直接在file函数中明确声明所有列的类型,确保排序键为非Nullable:
CREATE TABLE test_csv ORDER BY some_csv_column AS SELECT some_csv_column, some_other_column FROM file( 'myuserfiles/mydata.csv.gz', 'CSVWithNames', 'some_csv_column String, some_other_column Int32', 'gzip' );
这种方式完全可控,适合对数据类型有明确认知的场景。
- 临时表中转转换:先创建允许Nullable键的临时表导入数据,再通过
SELECT语句转换为目标表(同时处理可能的NULL值):
-- 创建临时表导入数据 CREATE TABLE temp_csv ORDER BY some_csv_column AS SELECT some_csv_column, some_other_column FROM file('myuserfiles/mydata.csv.gz', 'CSVWithNames', 'auto', 'gzip') SETTINGS allow_nullable_key = 1; -- 创建目标表并转换数据 CREATE TABLE test_csv ORDER BY some_csv_column AS SELECT assumeNotNull(some_csv_column) AS some_csv_column, some_other_column FROM temp_csv; -- 清理临时表 DROP TABLE temp_csv;
内容的提问来源于stack exchange,提问作者Alexandros
相关产品推荐
相关产品推荐

