Golang处理ClickHouse Decimal类型
在使用Golang处理ClickHouse的Decimal类型时遇到一些问题。官方driver在Scan时会将Decimal转为float64,导致精度丢失。尝试过用sql.RawBytes接收,但后续处理比较麻烦。请问有没有更好的方法能完整保留Decimal的精度?或者是否有推荐的第三方库可以正确处理这种类型?
2 回复
使用Go处理ClickHouse的Decimal类型时,推荐使用clickhouse-go驱动。可通过sql.RawBytes接收数据,再转换为字符串或自定义结构体处理。注意精度和标度设置,避免溢出。
更多关于Golang处理ClickHouse Decimal类型的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中处理ClickHouse的Decimal类型时,通常使用clickhouse-go驱动。以下是关键步骤和示例代码:
1. 安装驱动
go get github.com/ClickHouse/clickhouse-go/v2
2. 代码示例
package main
import (
"context"
"database/sql"
"fmt"
"log"
_ "github.com/ClickHouse/clickhouse-go/v2"
)
func main() {
// 连接ClickHouse
conn, err := sql.Open("clickhouse", "tcp://localhost:9000?username=default&password=")
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// 创建测试表(包含Decimal字段)
_, err = conn.Exec(`
CREATE TABLE IF NOT EXISTS decimal_test (
id UInt32,
amount Decimal(18, 4)
) ENGINE = Memory
`)
if err != nil {
log.Fatal(err)
}
// 插入数据
tx, _ := conn.Begin()
stmt, _ := tx.Prepare("INSERT INTO decimal_test (id, amount) VALUES (?, ?)")
// 使用字符串或float64传递Decimal值
_, err = stmt.Exec(1, "12345.6789") // 字符串形式
_, err = stmt.Exec(2, 98765.4321) // float64形式
if err != nil {
log.Fatal(err)
}
tx.Commit()
// 查询数据
rows, err := conn.Query("SELECT id, amount FROM decimal_test")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var (
id uint32
amount string // Decimal类型建议用字符串接收
)
if err := rows.Scan(&id, &amount); err != nil {
log.Fatal(err)
}
fmt.Printf("ID: %d, Amount: %s\n", id, amount)
}
}
3. 重要说明
- 精度定义:
Decimal(precision, scale)中precision是总位数,scale是小数位数 - 数据传递:
- 写入时支持字符串、float64或big.Int
- 读取时建议用string接收避免精度丢失
- 类型映射:
- ClickHouse Decimal → Go string/float64
- 大数值务必使用字符串避免精度问题
4. 处理建议
- 金融等精度敏感场景始终使用字符串传输
- 可自定义类型实现更精确的映射:
type Decimal string
func (d *Decimal) Scan(value interface{}) error {
*d = Decimal(fmt.Sprint(value))
return nil
}
使用此方案可确保Decimal数据在Golang和ClickHouse间准确传输。

