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

如何用GORM实现含UNION子查询的SQL?是否只能用Raw()?

GORM实现目标UNION ALL查询方案

问题分析

你的目标SQL里,两个UNION ALL的子查询逻辑是分开的:第一个只需要从models里展开tags,第二个需要关联projects并筛选公开项目后展开system_tags。你之前把整个UNION语句塞到Select里还加了全局的Joins,这会导致第一个子查询也被错误关联,不符合需求。

方案一:用GORM原生Union方法(推荐,GORM v2+支持)

GORM v2提供了Union和UnionAll方法,可以分别构建两个子查询再合并,完美匹配你的需求:

// 定义对应表的结构体示例
type Model struct {
    ID          uint
    Tags        []string `gorm:"type:text[]"` // 对应tags数组字段
    SystemTags  []string `gorm:"type:text[]"` // 对应system_tags数组字段
    ProjectID   uint
}

type Project struct {
    ID        uint
    IsPublic  bool
}

// 构建第一个子查询:展开tags字段
subQuery1 := db.Model(&Model{}).Select("unnest(tags) as tag_name")

// 构建第二个子查询:关联projects并筛选公开项目,展开system_tags
subQuery2 := db.Model(&Model{}).
    Select("unnest(system_tags) as tag_name").
    Joins("left join projects on projects.id = models.project_id").
    Where("projects.is_public = ?", true)

// 用UNION ALL合并两个子查询
unionSubQuery := subQuery1.UnionAll(subQuery2)

// 外层查询:筛选tag_name包含"12"(小写匹配)并排序
var tagNames []string
err := db.Model(&Model{}).
    Select("tag_name").
    From("(?) as tD", unionSubQuery). // 将合并后的子查询作为临时表tD
    Where("LOWER(tD.tag_name) LIKE ?", "%12%").
    Order("tag_name").
    Find(&tagNames).Error

if err != nil {
    // 处理错误逻辑
}

方案二:使用Raw方法(兼容所有GORM版本)

如果你的GORM版本较低不支持Union方法,或者觉得子查询构建太繁琐,可以直接用Raw方法,但一定要用参数化查询避免SQL注入:

var tagNames []string
sql := `
SELECT tag_name
FROM (
    SELECT unnest(tags) as tag_name FROM models
    UNION ALL
    SELECT unnest(system_tags) from models
    LEFT JOIN projects on projects.id = models.project_id 
    WHERE projects.is_public = true
) as tD 
WHERE LOWER(tD.tag_name) LIKE ? 
ORDER BY tag_name
`
err := db.Raw(sql, "%12%").Scan(&tagNames).Error

关键注意点

  • 不要把Joins和Where加在整个UNION查询上,要确保只有第二个子查询包含关联和筛选逻辑
  • 如果用Raw方法,务必通过?占位符传递参数,不要直接拼接字符串,防止SQL注入

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 22:10:34