MySQL 查询操作
QueryDB
根据条件查询的三种方式,当条件无效时会返回 ErrRecordNotFound 错误
- First
SELECT * FROM users ORDER BY id LIMIT 1;
- Take
SELECT * FROM users LIMIT 1;
- Last
SELECT * FROM users ORDER BY id DESC LIMIT 1;
Find 查询全表并返回条件结果,查询过程不会报错 ErrRecordNotFound db.Limit(1).Find(&user)
First/Last
First/Last 根据主键排序(// no primary key defined, results will be ordered by first field),返回第一条排序数据,将数组传递到指针对象
db.First(&user)db.Model(&User{}).First(&result)
根据主键查询
db.First(&user, 10)
// SELECT * FROM users WHERE id = 10;
db.First(&user, "10")
// SELECT * FROM users WHERE id = 10;
db.Find(&users, []int{1,2,3})
// SELECT * FROM users WHERE id IN (1,2,3);
根据条件查询
// Get first matched record
db.Where("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE name = 'jinzhu' ORDER BY id LIMIT 1;
// Get all matched records
db.Where("name <> ?", "jinzhu").Find(&users)
// SELECT * FROM users WHERE name <> 'jinzhu';
// IN
db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SELECT * FROM users WHERE name IN ('jinzhu','jinzhu 2');
// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)
// SELECT * FROM users WHERE name LIKE '%jin%';
// AND
db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' AND age >= 22;
// Time
db.Where("updated_at > ?", lastWeek).Find(&users)
// SELECT * FROM users WHERE updated_at > '2000-01-01 00:00:00';
// BETWEEN
db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
// SELECT * FROM users WHERE created_at BETWEEN '2000-01-01 00:00:00' AND '2000-01-08 00:00:00';
Query within struct/mapping
// Struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;
// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
// Slice of primary keys
db.Where([]int64{20, 21, 22}).Find(&users)
// SELECT * FROM users WHERE id IN (20, 21, 22);
struct 查询中只会查询非空值,不能采用默认值进行查询
db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu";
map 查询支持各种值,包含默认值查询
db.Where(map[string]interface{}{"Name": "jinzhu", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;
Not
db.Not("name = ?", "jinzhu").First(&user)
// SELECT * FROM users WHERE NOT name = "jinzhu" ORDER BY id LIMIT 1;
// Not In
db.Not(map[string]interface{}{"name": []string{"jinzhu", "jinzhu 2"}}).Find(&users)
// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
// Struct
db.Not(User{Name: "jinzhu", Age: 18}).First(&user)
// SELECT * FROM users WHERE name <> "jinzhu" AND age <> 18 ORDER BY id LIMIT 1;
// Not In slice of primary keys
db.Not([]int64{1,2,3}).First(&user)
// SELECT * FROM users WHERE id NOT IN (1,2,3) ORDER BY id LIMIT 1;
Or
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
// Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2", Age: 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);
// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2", "age": 18}).Find(&users)
// SELECT * FROM users WHERE name = 'jinzhu' OR (name = 'jinzhu 2' AND age = 18);
Order
db.Order("age desc, name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;
// Multiple orders
db.Order("age desc").Order("name").Find(&users)
// SELECT * FROM users ORDER BY age desc, name;
Limit
limit: 限量查询总数 offset: 查询起点
db.Limit(3).Find(&users)
// SELECT * FROM users LIMIT 3;
// Cancel limit condition with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SELECT * FROM users LIMIT 10; (users1)
// SELECT * FROM users; (users2)
db.Offset(3).Find(&users)
// SELECT * FROM users OFFSET 3;
db.Limit(10).Offset(5).Find(&users)
// SELECT * FROM users OFFSET 5 LIMIT 10;
// Cancel offset condition with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
// SELECT * FROM users OFFSET 10; (users1)
// SELECT * FROM users; (users2)
原生 SQL:派生列与函数(COALESCE / NULLIF / 计算列)
Gorm 帮我们拼 SQL,但有些查询用原生 SQL 更直接,尤其是需要从已有列「算」出新字段时。例如从 llm_providers 表列出所有提供商,并同时算出「展示名」和「是否配了密钥」:
SELECT
name,
COALESCE(NULLIF(display_name, ''), name) AS display_name,
enabled,
(api_key IS NOT NULL AND api_key != '') AS has_key
FROM llm_providers
ORDER BY name;
各列含义:
name:提供商标识(原表列)COALESCE(NULLIF(display_name, ''), name) AS display_name:展示名。内层NULLIF(display_name, '')把空串转成NULL,外层COALESCE(..., name)取第一个非NULL值——display_name为空时回退用nameenabled:是否启用(原表列)(api_key IS NOT NULL AND api_key != '') AS has_key:布尔计算列,密钥非空且非空串时为true,否则false
在 Go 里用 database/sql 读取(派生列要对应到普通变量,类型按数据库返回决定):
rows, err := db.Query(`
SELECT name,
COALESCE(NULLIF(display_name, ''), name),
enabled,
(api_key IS NOT NULL AND api_key != '') AS has_key
FROM llm_providers ORDER BY name`)
if err != nil {
log.Printf("query failed: %v", err)
return
}
defer rows.Close()
for rows.Next() {
var name, displayName string
var enabled, hasKey bool
if err := rows.Scan(&name, &displayName, &enabled, &hasKey); err != nil {
log.Printf("scan failed: %v", err)
continue
}
log.Printf("provider=%s display=%s enabled=%v hasKey=%v", name, displayName, enabled, hasKey)
}
if err := rows.Err(); err != nil { // 遍历结束必须检查读取过程中的错误
log.Printf("rows error: %v", err)
}
要点:
- 计算列(如
has_key)在 Go 端就是一个普通bool(数据库侧类型通常是boolean或tinyint) - 遍历完务必调用
rows.Err()检查,且别忘了defer rows.Close() - 占位符差异:MySQL 用
?,PostgreSQL 用$1/$2;本例无参数,故不涉及。通用机制见 数据库与 SQL