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

相关推荐
问道飞鱼3 小时前
【大数据知识】今天聊聊Clickhouse部署方案
大数据·clickhouse·部署
Fireworkitte2 天前
ClickHouse详解
clickhouse
知其_所以然4 天前
使用docker安装clickhouse集群
clickhouse·docker·容器
wuli玉shell4 天前
Doris和Clickhouse对比
clickhouse·doris
SelectDB技术团队7 天前
可观测性方案怎么选?SelectDB vs Elasticsearch vs ClickHouse
大数据·数据仓库·clickhouse·elasticsearch·信息可视化·doris·半结构化
goTsHgo7 天前
ClickHouse多表join的性能优化:原理与源码详解
clickhouse·性能优化
妖果yaoyao9 天前
docker 部署clickhouse
clickhouse·docker·容器
鱼鱼不愚与10 天前
处理 Clickhouse 内存溢出
数据库·分布式·clickhouse
Wonderful_一直有你10 天前
clickhouse - 重新建表覆盖旧表-解决分区时间错误问题-197001
clickhouse
千月落12 天前
ClickHouse副本集群
服务器·数据库·clickhouse