如何使用gorm-clickhouse读取ClickHouse的WITH TOTALS行?
通过GORM获取ClickHouse WITH TOTALS数据的可行方案
由于GORM本身没有封装ClickHouse的WITH TOTALS特性,但可以结合底层的clickhouse-go驱动能力实现需求,同时支持用map[string]interface{}接收主结果和总计数据,具体方案如下:
核心思路:Raw查询+底层Rows解析
用GORM执行带WITH TOTALS的原生SQL,将返回的Rows对象类型断言为clickhouse-go的Rows,利用其自带的HasTotals()和Totals()方法提取总计数据,再手动解析为map[string]interface{}格式。
代码示例
package main import ( "context" "github.com/ClickHouse/clickhouse-go/v2" "gorm.io/driver/clickhouse" "gorm.io/gorm" ) func main() { ctx := context.Background() // 初始化GORM连接ClickHouse db, err := gorm.Open(clickhouse.New(clickhouse.Config{ DSN: "tcp://localhost:9000?database=default&username=default&password=", }), &gorm.Config{}) if err != nil { panic(err) } // 执行带WITH TOTALS的原生查询 sql := "SELECT category, count(id) AS cnt FROM orders GROUP BY category WITH TOTALS" rows, err := db.Raw(sql).Rows() if err != nil { panic(err) } defer rows.Close() // 类型断言为clickhouse-go的Rows对象,获取底层驱动能力 chRows, ok := rows.(*clickhouse.Rows) if !ok { panic("无法将rows转换为clickhouse.Rows类型") } // 获取查询列名,用于构造map的key cols, err := chRows.Columns() if err != nil { panic(err) } // 解析主结果集到map切片 var mainResults []map[string]interface{} for chRows.Next() { // 初始化值容器 values := make([]interface{}, len(cols)) for i := range values { values[i] = new(interface{}) } // 扫描当前行数据 if err := chRows.Scan(values...); err != nil { panic(err) } // 构造单条结果map item := make(map[string]interface{}, len(cols)) for i, col := range cols { item[col] = *(values[i].(*interface{})) } mainResults = append(mainResults, item) } // 解析总计数据到map var totals map[string]interface{} if chRows.HasTotals() { totalsRow := chRows.Totals() values := make([]interface{}, len(cols)) for i := range values { values[i] = new(interface{}) } if err := totalsRow.Scan(values...); err != nil { panic(err) } totals = make(map[string]interface{}, len(cols)) for i, col := range cols { totals[col] = *(values[i].(*interface{})) } } // 输出结果示例 println("主结果:") for _, item := range mainResults { println(item["category"], item["cnt"]) } println("\n总计:") if totals != nil { println(totals["category"], totals["cnt"]) } }
关键注意事项
- 必须使用
github.com/ClickHouse/clickhouse-go/v2版本的驱动,GORM的clickhouse驱动依赖该版本,低版本可能不支持Rows.Totals()方法。 - 类型断言需确保GORM连接的是ClickHouse数据库,实际代码中建议用更温和的错误处理替代panic。
- 操作完成后务必关闭Rows对象,避免数据库连接泄漏。
内容的提问来源于stack exchange,提问作者zzz TDT
相关产品推荐
相关产品推荐

