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·源码解析·副本同步
努力做一名技术6 小时前
从 Elastic 到 ClickHouse:日志系统性能与成本优化之路
clickhouse
白眼黑刺猬6 小时前
ClickHouse 高性能实时分析数据库-物化视图篇
clickhouse
Fireworkitte6 小时前
ClickHouse 常用的使用场景
clickhouse
小牛头#17 天前
clickhouse 各个引擎适用的场景
大数据·clickhouse·机器学习
全干engineer17 天前
ClickHouse 入门详解:它到底是什么、优缺点、和主流数据库对比、适合哪些场景?
数据库·clickhouse
爱吃萝卜的猪17 天前
Clickhouse诊断工具之chdig
clickhouse
源图客17 天前
ClickHouse介绍与应用
clickhouse
码农周17 天前
ClickHouse 时间范围查询:精准筛选「本月数据」
clickhouse
积跬步,慕至千里19 天前
clickhouse数据库表和doris数据库表迁移starrocks数据库时建表注意事项总结
数据库·clickhouse