ClickHouse进行LEFT JOIN 关联查询时, 关联键的数据类型不一致,导致报错 的解决方案详解

一.场景

使用golang语言操作ClickHouse数据库进行LEFT JOIN关联查询查询计算: 关联键在不同数据表中的数据类型不一致, 这样SQL语句就会报错,

二.问题

通过上面场景描述, 下面贴出具体的sql语句相关:

  • 表user_phone_bind:
    • 字段UserId(用户id): 类型Int64
    • 字段Phone(手机号): 类型String
  • 表user_order:
    • 字段UserId(用户id): 类型UInt64
    • 字段OrderId(订单id): 类型UInt64
    • 字段OrderNo(订单号):

现在需要查询user_order表中的订单号,以及对应用户当前绑定的手机号,这里通过LEFT JOIN 进行连接查询, 对应的sql语句如下:

sql 复制代码
// 查询订单表订单信息(订单号),以及用户最新绑定的手机号
SELECT OrderNo, user_bind_phone.Phone AS phone FROM user_order LEFT JOIN (SELECT (UserId,argMax(Phone, CreatedAt) AS phone FROM user_bind_phone GROUP BY UserId) ON user_order.UserId = user_bind_phone.UserId

// 对上述sql语句说明: 
// 查询用户订单编号,以及用户绑定的手机号, 这里使用LEFT JOIN 连接,查询user_bind_phone中用户的手机号,argMax(Phone, CreatedAt) 表示返回最大值CreatedAt(也就是最新一条)的Phone记录, 这里user_order与user_bind_phone表通过UserId进行关联 
	

通过执行上面sql语句,报如下错误:

sql 复制代码
message: Can't infer common type for joined columns: UserId: UInt64 at left, bupb.UserId: Int64 at right. There is no supertype for types UInt64, Int64 because some of them are signed integers and some are unsigned integers, but there is no signed integer type, that can exactly represent all required unsigned integer values"

三.错误原因

在使用 ClickHouse 进行表连接(JOIN)时出现的,主要是因为连接的两个表中对应的列类型不匹配

四.错误分析

  • 列类型不一致:
    • 当前错误信息中提到的 UserId 列在左侧表的类型是 UInt64(无符号 64 位整数),而在右侧表的类型是 Int64(有符号 64 位整数)
    • UInt64 可以存储更大的非负整数,而 Int64 可以存储正负整数。由于它们的类型不同,ClickHouse 无法推断出一个共同的类型来进行连接
  • 类型不兼容
    • ​​​​​​​由于无符号整数和有符号整数之间没有一个可以涵盖所有值的共同类型,因此引发了这个错误

五.解决方案

1.类型转换

在连接查询中可以使用类型转换函数将 UserId 列的类型进行转换,以使两者类型一致,可以将 Int64 转换为 UInt64,或者将 UInt64 转换为 Int64,具体取决于各自数据特性和需求,eg:

sql 复制代码
// 方法1: 将 Int64 转换为 UInt64
SELECT OrderNo, user_bind_phone.Phone AS phone FROM user_order LEFT JOIN (SELECT (UserId,argMax(Phone, CreatedAt) AS phone FROM user_bind_phone GROUP BY UserId) ON user_order.UserId = CAST(user_bind_phone.UserId AS UInt64)

// 方法2: 将 UInt64 转换为 Int64
SELECT OrderNo, user_bind_phone.Phone AS phone FROM user_order LEFT JOIN (SELECT (UserId,argMax(Phone, CreatedAt) AS phone FROM user_bind_phone GROUP BY UserId) ON CAST(user_order.UserId AS Int64) = user_bind_phone.UserId

// 方法3: 在Select中进行CAST处理
SELECT OrderNo, user_bind_phone.Phone AS phone FROM user_order LEFT JOIN (SELECT ((CAST(UserId AS UInt64)) AS UserId,argMax(Phone, CreatedAt) AS phone FROM user_bind_phone GROUP BY UserId) ON user_order.UserId = user_bind_phone.UserId

2.检查数据范围

在进行类型转换前,请确保数据在转换后不会导致溢出或数据丢失。例如,UInt64 的范围是 0 到 18,446,744,073,709,551,615,而 Int64 的范围是 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807。因此,如果您将 UInt64 转换为 Int64,请确保数据不会超出 Int64 的正值范围

3.调整数据模型

如果可能,考虑在数据模型设计时统一使用同一种类型(例如,统一使用 UInt64Int64),以减少此类类型不匹配的问题

六.总结

在 ClickHouse 中,当进行表连接时,确保连接的列类型一致是非常重要的。如果您遇到列类型不匹配的错误,可以通过类型转换来解决。选择合适的转换方式并确保数据的范围是关键步骤

相关推荐
降世神童18 小时前
大数据系列 | 详解基于Zookeeper或ClickHouse Keeper的ClickHouse集群部署--完结
大数据·clickhouse·zookeeper
南客先生2 天前
海量聊天消息处理:ShardingJDBC分库分表、ClickHouse冷热数据分离、ES复合查询方案、Flink实时计算与SpringCloud集成
java·clickhouse·elasticsearch·flink·springcloud·shardingjdbc
曹弘毅2 天前
doris/clickhouse常用sql
数据库·sql·clickhouse·doris
晴天彩虹雨2 天前
实时数仓体系概览与架构演进
数据仓库·clickhouse·架构·flink·kafka
Hehuyi_In3 天前
阿里云Clickhouse 冷热数据分层存储 实战记录
clickhouse·oss·存储·归档·冷热分层
weisian1514 天前
中间件--ClickHouse-10--海量数据存储如何抉择ClickHouse和ES?
clickhouse·elasticsearch·中间件
D愿你归来仍是少年5 天前
Clickhouse 配置参考
大数据·clickhouse
weisian1516 天前
中间件--ClickHouse-14--案例-3-其他案例思路概述
clickhouse·中间件