动态SQL拼接NULL字段必须先判Valid再生成对应SQL片段:Valid为true时拼name = 'xxx',false时拼name IS NULL;INSERT/UPDATE中需显式写NULL字面量并转义非NULL值,避免语义错误与注入风险。

动态SQL拼接时,NULL字段怎么不崩还能保持语义
直接把 sql.NullString 或 *string 往 SQL 字符串里拼,八成会出错——不是 panic 就是生成错误的 WHERE 条件。动态 SQL 的本质是字符串组装,而 NULL 在 SQL 里是关键字,不是字符串字面量,更不能当空串处理。
- 别写
"WHERE name = '" + ns.String + "'":当ns.Valid == false时,ns.String是空串,结果变成WHERE name = '',语义完全错乱 - 也别用
fmt.Sprintf("'%s'", ns.String):同样忽略Valid,且对 NULL 场景毫无区分 - 正确做法是先判断语义再生成片段:若
ns.Valid为 true,拼"name = 'xxx'";若 false,拼"name IS NULL" - 批量条件建议封装辅助函数,比如
sqlNullEq("name", &ns)返回"name IS NULL"或"name = 'xxx'"
WHERE子句里混用NULL和空字符串,怎么写才不踩坑
业务常要求“查 nickname 为空或未填写”,但数据库里可能存的是 ''(空字符串)或 NULL,二者在 SQL 中不等价,Go 层必须显式区分。
-
NULL对应IS NULL,''对应= '',不能合并成IS NULL OR = ''—— MySQL 允许,但 PostgreSQL 会报错 - 如果字段类型是
sql.NullString,需拆成两个分支:if ns.Valid && ns.String == ""表示空字符串;!ns.Valid表示 NULL - 若用
*string,则ns == nil是 NULL,*ns == ""是空字符串,注意解引用前判空 - 避免写
COALESCE(nickname, '') = '':虽然能统一语义,但会破坏索引,查询变慢
INSERT/UPDATE语句中,如何让NULL字段自动跳过或显式置NULL
动态构建 INSERT 时,不能靠“字段没值就不写”来省事——这会导致列数与值数不匹配,SQL 直接报错。必须明确哪些字段要写、哪些要设为 NULL。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 字段列表和 VALUES 列表必须严格对齐;若某字段要设为 NULL,VALUES 中对应位置必须写
NULL字面量,不能留空 - 对
sql.NullString,生成值部分前检查:if ns.Valid { values = append(values, "'"+escape(ns.String)+"'") } else { values = append(values, "NULL") } - 对
*string,同理:if ns != nil { ... } else { ... } - 别依赖驱动自动转
nil→NULL:那是db.Exec用args...时的行为,手动拼 SQL 时不生效 - 注意单引号转义:哪怕只拼非 NULL 值,也要对
ns.String做 SQL 字符串转义,否则注入风险
用QueryRow.Scan接收动态查询结果时,NULL字段怎么安全取值
动态 SQL 可能返回任意列,你没法提前定义 struct 字段类型。这时硬套 sql.NullString 不现实,但也不能用 interface{} 然后暴力断言。
立即学习“go语言免费学习笔记(深入)”;
- 最稳妥是用
[]interface{}接收所有列,再按sql.NullString的逻辑逐个解析:v := values[i]; if v == nil { /* NULL */ } else { s := v.(string) /* 非 NULL 字符串 */ } - MySQL 驱动返回的
nil就代表 SQL NULL;PostgreSQL 驱动同理;但 SQLite 驱动可能返回""或0,得看具体 driver 实现 - 别用
fmt.Sprint(v)判断是否为空:nil 指针打印出来是<nil></nil>,但字符串""和整数0也会被误判 - 如果知道某列类型,可提前声明
var s sql.NullString,然后row.Scan(&s)—— 即使是动态 SQL,只要列顺序固定,就能复用这套逻辑
动态 SQL 处理 NULL 的核心不是“怎么拼”,而是“什么时候该用 IS NULL、什么时候该用 = ''、什么时候该跳过字段”。这些判断点藏在业务逻辑里,而不是 SQL 字符串里。漏掉一个 Valid 检查,就可能把 “用户没填邮箱” 和 “用户填了空邮箱” 当成一回事。

















