ent相同列名排序问题解决

前言

最近在开发的时候,需要进行数据库计算,主要是根据表中的某些字段进行汇总计算,但由于数据库表中已有同名字段名,ent 不会使用计算后的指标,默认使用schema中定义的字段,导致无法返回正确的结果。

针对这种情况,我能想到的方法有2种: 1) 不使用同名的字段名 2) 查找ent是否有相关的解决方案。

这里我采用了第二种方法,查找相关的issues, 通过查找相关issue,找到了相关的解决方案: ent 的 sql/modifier 特性。

场景重现

定义一个新的数据库表结构,结构如下:

go 复制代码
func (Ad) Fields() []ent.Field {
    return []ent.Field{
        field.Float("estimated_earnings"),
        field.Int("page_views"),
        field.Time("date"),
        field.Float("page_views_rpm").Optional(),
    }
}

page_views_rpm 字段是由 estimated_earnings 和 page_views 计算而来。

编写相应的查询代码:

go 复制代码
package main

import (
	"context"
	"entgo.io/ent/dialect/sql"
	"fmt"
	_ "github.com/lib/pq"
	"log"
	"modifier-demo/ent"
	"modifier-demo/ent/ad"
	"time"
)

type Ads struct {
	EstimatedEarnings float64   `json:"estimated_earnings"`
	PageViews         int64     `json:"page_views"`
	Date              time.Time `json:"date"`
	PageViewsRpm      float64   `json:"page_views_rpm"`
}

func main() {
	client, err := ent.Open("postgres", "host=127.0.0.1 port=5432 sslmode=disable user=postgres dbname=data_test password=mysecretpassword")
	if err != nil {
		log.Fatalf("failed opening connection to postgres: %v", err)
	}
	defer client.Close()
	// Run the auto migration tool.
	if err := client.Schema.Create(context.Background()); err != nil {
		log.Fatalf("failed creating schema resources: %v", err)
	}
	var a []Ads
	err = client.Debug().Ad.Query().Order(ent.Desc(ad.FieldPageViewsRpm)).GroupBy(ad.FieldDate).Aggregate(func(selector *sql.Selector) string {
		return sql.As(" CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views)*1.0, 0.0)*1000, 0)AS numeric(10,2))", "page_views_rpm")
	}).Scan(context.TODO(), &a)
	if err != nil {
		return
	}
	fmt.Println(a)
}

主要是根据date来汇总并重新计算 page_views_rpm 字段,运行代码后发现没有成功输出,打印后发现ent使用了旧的PageViewsRpm字段进行排序,导致sql无法顺利运行。

sql 复制代码
SELECT "ads"."date",
       CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views) * 1.0, 0.0) * 1000,
                     0) AS numeric(10,2)) AS "page_views_rpm"
FROM "ads"
GROUP BY "ads"."date"
ORDER BY "ads"."page_views_rpm" 

解决

这里可以使用 ent 的 feature sql/modifier 来解决,我们先在 generate.go 开启特性 --feature sql/modifier,然后重新生成代码,使用Modify方法添加自定义修饰符即可,相应的代码如下:

go 复制代码
	err = client.Debug().Ad.Query().Modify(func(s *sql.Selector) {
		s.Select(sql.As(" CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views)*1.0, 0.0)*1000, 0)AS numeric(10,2))", "page_views_rpm")).
			GroupBy("date").
			OrderBy("page_views_rpm")
	}).Scan(context.TODO(), &a)
	if err != nil {
		return
	}

运行修改后的代码,结果顺利输出,相应的sql如下:

sql 复制代码
SELECT CAST(COALESCE(SUM(estimated_earnings) / NULLIF(SUM(page_views) * 1.0, 0.0) * 1000,
                     0) AS numeric(10, 2)) AS "page_views_rpm"
FROM "ads"
GROUP BY "date"
ORDER BY "page_views_rpm"

参考

相关推荐
Spider Cat 蜘蛛猫7 小时前
Springboot SSO系统设计文档
java·spring boot·后端
zyk_computer8 小时前
AI 时代,或许 Rust 比 Python 更合适
人工智能·后端·python·ai·rust·ai编程·vibe coding
雨辰AI8 小时前
SpringBoot3 项目国产化改造完整流程|从 MySQL 到人大金仓落地
java·数据库·后端·mysql·政务
GreenTea10 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 6 章 Benchmark 与优化路线图
后端
Rust语言中文社区10 小时前
【Rust日报】2026-05-14 Pyrefly v1.0 正式发布:快速的 Python 类型检查器和语言服务器
开发语言·后端·python·rust
GreenTea10 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 5 章 SQL → 逻辑计划 → 物理计划
后端
GreenTea10 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 4 章 哈希聚合:GROUP BY 的核心
后端
IT_陈寒10 小时前
Vue的v-for为什么不加key也能工作?我差点翻车
前端·人工智能·后端
GreenTea10 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 3 章 表达式系统:把 SQL 表达式变成可执行树
后端
GreenTea10 小时前
【Rust 2026教程:从零构建 Mini-OLAP 引擎】第 2 章 向量化执行:让 CPU 跑满
后端