squirrel不是拼接而是构建sql,必须通过链式方法或sqlizer接口组合,混用字符串拼接会破坏参数安全、类型检查和跨库兼容性。

直接说结论:Squirrel 不是“拼接”SQL,而是“构建”SQL;它不接受字符串拼接式写法,所有逻辑必须通过链式方法或 Sqlizer 接口组合,否则会丢失参数安全、类型检查和跨库兼容性。
为什么不能用字符串拼接 + Squirrel 混用
常见错误是试图把 squirrel.Select("id").From("users") 和手写的 " AND status = 'active'" 拼在一起。这会导致:
-
ToSql()生成的参数列表([]interface{})和你硬编码的字符串完全脱节,执行时参数错位或缺失 - 手动拼的字符串绕过 Squirrel 的转义机制,一旦含用户输入,立刻触发 SQL 注入
- 后续加
OrderBy或Limit时,语法顺序混乱,ToSql()可能 panic
Where 条件里混合 AND/OR 必须显式分组
默认 Where 是扁平 AND 连接,不会自动加括号。比如查 “status 是 active 或 pending,且 created_at 在最近 7 天内”,下面写法是错的:
squirrel.Select("*").From("users").
Where("status = ?", "active").
Where("status = ?", "pending").
Where("created_at > ?", weekAgo)
它生成的是 status = 'active' AND status = 'pending' AND created_at > ?,永远为 false。
正确做法是用 squirrel.Or 和 squirrel.And 显式嵌套:
squirrel.Select("*").From("users").
Where(squirrel.And{
squirrel.Or{
squirrel.Eq{"status": "active"},
squirrel.Eq{"status": "pending"},
},
squirrel.Gt{"created_at": weekAgo},
})
IN 查询传 slice 时必须配对占位符格式
MySQL 和 PostgreSQL 对 IN (?, ?, ?) 的占位符风格不同:
- PostgreSQL 默认用
$1, $2, $3(squirrel.Dollar) - MySQL 必须用
?, ?, ?(squirrel.Question)
如果没调 PlaceholderFormat 就直接丢给 MySQL,会报 ERROR 1064。正确写法:
builder := squirrel.Select("*").From("users").
Where(squirrel.Eq{"id": []int{1, 2, 3}})
// MySQL 场景下必须加这一句
builder = builder.PlaceholderFormat(squirrel.Question)
sql, args, _ := builder.ToSql()
UNION ALL 不是 Squirrel 原生支持的操作
Squirrel 没有 Union 或 UnionAll 方法。遇到多子查询合并场景(如按日分表查询),得放弃链式构建,改用原生字符串组装:
- 用
fmt.Sprintf构造每个子查询,%q自动处理单引号与转义 - 用
strings.Join(parts, " UNION ALL ")合并,避免首尾多出UNION ALL - 切忌把子查询的
args混进主查询——每个子查询应独立参数化,或统一改用命名参数(如sqlx.NamedExec)
最易被忽略的一点:Squirrel 的 Builder 是一次性对象,调过 ToSql() 后状态不可复用;若需多次生成相似查询(如分页循环),每次都要新建 Builder 实例,而不是缓存后反复修改。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











