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

相关推荐
问道飞鱼6 天前
【大数据技术】ClickHouse配置详细解读
大数据·clickhouse·配置信息
StarRocks_labs7 天前
StarRocks 助力印度领先即时零售平台 Zepto 构建实时洞察能力
大数据·starrocks·clickhouse·存算一体·postgres mvp
奋进的白羊9 天前
clickhouse使用问题记录
数据库·clickhouse
JeffreyGu.9 天前
clickhouse-backup备份
数据库·clickhouse
hkNaruto10 天前
【大数据】clickhouse快速上手
大数据·clickhouse
言之。20 天前
简单介绍一下Clickhouse及其引擎
clickhouse
西京刀客20 天前
clickhouse的UInt64类型(countIf() 函数返回)
clickhouse·uint64·countif
Super_King_21 天前
ClickHouse 中 ORDER BY 场景下 arrayExists 与 hasAny 性能深入研究:布隆过滤器索引的影响分析
clickhouse
Super_King_21 天前
深入研究:ClickHouse中arrayExists与hasAny在ORDER BY场景下的性能差异
clickhouse