You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在go-jet中构建CASE条件实现字段空值判断与日期比较

解决go-jet中CASE条件无法作为布尔表达式用于Where()的问题

问题背景

需要实现表中AffectedTo字段的判断逻辑:若该字段为null则返回true,若非null则与输入日期比较。使用go-jet的CASE条件时,无法直接得到布尔表达式用于Where();尝试用caseCondition.IS_NOT_NULL()获取布尔表达式,但因caseCondition本身非空,该语句始终返回true。

依赖库与原代码

package postgres

import (
    "context"
    "errors"
    "fmt"
    "time"

    "financing-offer/internal/core/entity"
    "financing-offer/internal/database"
    "financing-offer/internal/database/dbmodels/finoffer/public/enum"
    "financing-offer/internal/database/dbmodels/finoffer/public/model"
    "financing-offer/internal/database/dbmodels/finoffer/public/table"

    "github.com/go-jet/jet/v2/postgres"
    "github.com/go-jet/jet/v2/qrm"
)
func (b *BlackListSymbolRepository) GetByAffectTime(ctx context.Context, symbolId int64, affectedFrom time.Time, affectedTo time.Time) ([]entity.BlacklistSymbol, error) {
    // Create a CASE condition
    caseCondition := postgres.CASE().
        WHEN(table.BlacklistSymbol.AffectedTo.IS_NULL()).THEN(postgres.Bool(true)).
        ELSE(table.BlacklistSymbol.AffectedTo.GT(postgres.TimestampT(affectedFrom)))

    // Combine the conditions in the WHERE clause
    stm := table.BlacklistSymbol.SELECT(table.BlacklistSymbol.AllColumns).
        WHERE(
            table.BlacklistSymbol.SymbolID.EQ(postgres.Int64(symbolId)).
                AND(table.BlacklistSymbol.Status.EQ(enum.Blacklistsymbolstatus.Active)).
                AND(table.BlacklistSymbol.AffectedFrom.LT_EQ(postgres.TimestampT(affectedTo))).
                AND(caseCondition.IS_NOT_NULL()), // Use the CASE condition
        )

    dest := make([]model.BlacklistSymbol, 0)
    if err := stm.QueryContext(ctx, b.getDbFunc(ctx), &dest); err != nil {
        if errors.Is(err, qrm.ErrNoRows) {
            return []entity.BlacklistSymbol{}, nil
        }
        return nil, fmt.Errorf("BlackListSymbolRepository GetByAffectTime %w", err)
    }
    return MapBlacklistSymbolsDbToEntity(dest), nil
}

解决方案

方案一:用OR组合条件(推荐)

你的逻辑可以直接简化为(AffectedTo IS NULL OR AffectedTo > affectedFrom),这种写法更符合SQL规范,数据库也更容易生成优化的查询计划,无需使用CASE。

修改后的代码:

func (b *BlackListSymbolRepository) GetByAffectTime(ctx context.Context, symbolId int64, affectedFrom time.Time, affectedTo time.Time) ([]entity.BlacklistSymbol, error) {
    // 直接用OR组合判断逻辑
    affectedToCondition := table.BlacklistSymbol.AffectedTo.IS_NULL().
        OR(table.BlacklistSymbol.AffectedTo.GT(postgres.TimestampT(affectedFrom)))

    stm := table.BlacklistSymbol.SELECT(table.BlacklistSymbol.AllColumns).
        WHERE(
            table.BlacklistSymbol.SymbolID.EQ(postgres.Int64(symbolId)).
                AND(table.BlacklistSymbol.Status.EQ(enum.Blacklistsymbolstatus.Active)).
                AND(table.BlacklistSymbol.AffectedFrom.LT_EQ(postgres.TimestampT(affectedTo))).
                AND(affectedToCondition), // 直接传入布尔条件
        )

    dest := make([]model.BlacklistSymbol, 0)
    if err := stm.QueryContext(ctx, b.getDbFunc(ctx), &dest); err != nil {
        if errors.Is(err, qrm.ErrNoRows) {
            return []entity.BlacklistSymbol{}, nil
        }
        return nil, fmt.Errorf("BlackListSymbolRepository GetByAffectTime %w", err)
    }
    return MapBlacklistSymbolsDbToEntity(dest), nil
}

方案二:正确使用CASE表达式

若坚持使用CASE,需要明确将CASE的结果与true比较——go-jet的CASE表达式返回的是Expression类型,必须转换为布尔条件才能用于Where(),无需调用IS_NOT_NULL()。

修改后的CASE部分代码:

// 正确构建CASE布尔条件
caseCondition := postgres.CASE().
    WHEN(table.BlacklistSymbol.AffectedTo.IS_NULL()).THEN(postgres.Bool(true)).
    ELSE(table.BlacklistSymbol.AffectedTo.GT(postgres.TimestampT(affectedFrom))).
    END().EQ(postgres.Bool(true)) // 判断CASE结果为true

// 在WHERE中直接使用
AND(caseCondition)

内容的提问来源于stack exchange,提问作者JackAndrea

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 14:18:35