1. 查询

    原生 SQL

    1. db.Where("name = ?", "jinzhu").First(&user)
    2. //// SELECT * FROM users WHERE name = 'jinzhu' limit 1;
    3. // 获取所有匹配的记录
    4. db.Where("name = ?", "jinzhu").Find(&users)
    5. //// SELECT * FROM users WHERE name = 'jinzhu';
    6. // <>
    7. db.Where("name <> ?", "jinzhu").Find(&users)
    8. // IN
    9. db.Where("name in (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)
    10. // LIKE
    11. db.Where("name LIKE ?", "%jin%").Find(&users)
    12. // AND
    13. db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
    14. // Time
    15. db.Where("updated_at > ?", lastWeek).Find(&users)
    16. // BETWEEN
    17. db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)

    Struct & Map

    1. // Struct
    2. db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
    3. //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;
    4. // Map
    5. db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
    6. //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
    7. // 多主键 slice 查询
    8. db.Where([]int64{20, 21, 22}).Find(&users)
    9. //// SELECT * FROM users WHERE id IN (20, 21, 22);

    NOTE 当通过struct进行查询的时候,GORM 将会查询这些字段的非零值, 意味着你的字段包含 0''false 或者其他 , 将不会出现在查询语句中, 例如:

    1. db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
    2. //// SELECT * FROM users WHERE name = "jinzhu";

    你可以考虑适用指针类型或者 scanner/valuer 来避免这种情况。

    1. // 使用指针类型
    2. type User struct {
    3. gorm.Model
    4. Name string
    5. Age *int
    6. }
    7. // 使用 scanner/valuer
    8. type User struct {
    9. gorm.Model
    10. Name string
    11. Age sql.NullInt64
    12. }

    1.1.2. Not

    Where查询类似

    1. db.Not("name", "jinzhu").First(&user)
    2. //// SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;
    3. // 不包含
    4. db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)
    5. //// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
    6. //不在主键 slice 中
    7. db.Not([]int64{1,2,3}).First(&user)
    8. db.Not([]int64{}).First(&user)
    9. //// SELECT * FROM users;
    10. // 原生 SQL
    11. db.Not("name = ?", "jinzhu").First(&user)
    12. //// SELECT * FROM users WHERE NOT(name = "jinzhu");
    13. // Struct
    14. db.Not(User{Name: "jinzhu"}).First(&user)
    15. //// SELECT * FROM users WHERE name <> "jinzhu";

    1.1.3. Or

    1. db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
    2. //// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
    3. // Struct
    4. //// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';
    5. // Map
    6. db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)
    7. //// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';

    1.1.4. 行内条件查询

    Where 查询类似。

    需要注意的是,当使用链式调用传入行内条件查询时,这些查询不会被传参给后续的中间方法。

    1. // 通过主键进行查询 (仅适用于主键是数字类型)
    2. db.First(&user, 23)
    3. //// SELECT * FROM users WHERE id = 23 LIMIT 1;
    4. // 非数字类型的主键查询
    5. db.First(&user, "id = ?", "string_primary_key")
    6. //// SELECT * FROM users WHERE id = 'string_primary_key' LIMIT 1;
    7. // 原生 SQL
    8. db.Find(&user, "name = ?", "jinzhu")
    9. //// SELECT * FROM users WHERE name = "jinzhu";
    10. db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)
    11. //// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
    12. // Struct
    13. db.Find(&users, User{Age: 20})
    14. //// SELECT * FROM users WHERE age = 20;
    15. // Map
    16. db.Find(&users, map[string]interface{}{"age": 20})
    17. //// SELECT * FROM users WHERE age = 20;

    1.1.5. 额外的查询选项

    1.2. FirstOrInit

    获取第一条匹配的记录,或者通过给定的条件下初始一条新的记录(仅适用与于 struct 和 map 条件)。

    1. // 未查询到
    2. db.FirstOrInit(&user, User{Name: "non_existing"})
    3. //// user -> User{Name: "non_existing"}
    4. // 查询到
    5. db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)
    6. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
    7. db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
    8. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
    1. // 未查询到
    2. db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
    3. //// SELECT * FROM USERS WHERE name = 'non_existing';
    4. //// user -> User{Name: "non_existing", Age: 20}
    5. db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user)
    6. //// SELECT * FROM USERS WHERE name = 'non_existing';
    7. //// user -> User{Name: "non_existing", Age: 20}
    8. // 查询到
    9. db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)
    10. //// SELECT * FROM USERS WHERE name = jinzhu';
    11. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}

    1.2.2. Assign

    无论是否查询到数据,都将参数赋值给 struct

    1. // 未查询到
    2. db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
    3. //// user -> User{Name: "non_existing", Age: 20}
    4. // 查询到
    5. db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)
    6. //// SELECT * FROM USERS WHERE name = jinzhu';
    7. //// user -> User{Id: 111, Name: "Jinzhu", Age: 30}

    获取第一条匹配的记录,或者通过给定的条件创建一条记录 (仅适用与于 struct 和 map 条件)。

    1. // 未查询到
    2. db.FirstOrCreate(&user, User{Name: "non_existing"})
    3. //// INSERT INTO "users" (name) VALUES ("non_existing");
    4. //// user -> User{Id: 112, Name: "non_existing"}
    5. // 查询到
    6. db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
    7. //// user -> User{Id: 111, Name: "Jinzhu"}

    1.3.1. Attrs

    如果未查询到记录,通过给定的参数赋值给 struct ,然后使用这些值添加一条记录。

    1. // 未查询到
    2. db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
    3. //// SELECT * FROM users WHERE name = 'non_existing';
    4. //// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
    5. //// user -> User{Id: 112, Name: "non_existing", Age: 20}
    6. // 查询到
    7. db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
    8. //// SELECT * FROM users WHERE name = 'jinzhu';
    9. //// user -> User{Id: 111, Name: "jinzhu", Age: 20}

    1.3.2. Assign

    无论是否查询到,都将其分配给记录,并保存到数据库中。

    1. // 未查询到
    2. db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
    3. //// SELECT * FROM users WHERE name = 'non_existing';
    4. //// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
    5. // 查询到
    6. db.Where(User{Name: "jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
    7. //// SELECT * FROM users WHERE name = 'jinzhu';
    8. //// UPDATE users SET age=30 WHERE id = 111;
    9. //// user -> User{Id: 111, Name: "jinzhu", Age: 30}

    1.4. 高级查询

    1.4.1. 子查询

    使用 *gorm.expr 进行子查询

    1. db.Where("amount > ?", DB.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").QueryExpr()).Find(&orders)
    2. // SELECT * FROM "orders" WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders" WHERE (state = 'paid')));

    指定要从数据库检索的字段,默认情况下,将选择所有字段。

    1.4.3. Order

    1. db.Order("age desc, name").Find(&users)
    2. //// SELECT * FROM users ORDER BY age desc, name;
    3. // 多个排序条件
    4. db.Order("age desc").Order("name").Find(&users)
    5. //// SELECT * FROM users ORDER BY age desc, name;
    6. // 重新排序
    7. db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
    8. //// SELECT * FROM users ORDER BY age desc; (users1)
    9. //// SELECT * FROM users ORDER BY age; (users2)

    1.4.4. Limit

    指定要查询的最大记录数

    1. db.Limit(3).Find(&users)
    2. //// SELECT * FROM users LIMIT 3;
    3. // 用 -1 取消 LIMIT 限制条件
    4. db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
    5. //// SELECT * FROM users LIMIT 10; (users1)
    6. //// SELECT * FROM users; (users2)

    1.4.5. Offset

    指定在开始返回记录之前要跳过的记录数。

    1. db.Offset(3).Find(&users)
    2. //// SELECT * FROM users OFFSET 3;
    3. // 用 -1 取消 OFFSET 限制条件
    4. db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
    5. //// SELECT * FROM users OFFSET 10; (users1)
    6. //// SELECT * FROM users; (users2)

    1.4.6. Count

    获取模型记录数

    1. db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
    2. //// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
    3. //// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)
    4. db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
    5. //// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)
    6. db.Table("deleted_users").Count(&count)
    7. //// SELECT count(*) FROM deleted_users;

    注意: 在查询链中使用 Count 时,必须放在最后一个位置,因为它会覆盖 SELECT 查询条件。

    1. rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
    2. for rows.Next() {
    3. ...
    4. }
    5. rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
    6. for rows.Next() {
    7. ...
    8. }
    9. type Result struct {
    10. Date time.Time
    11. Total int64
    12. }
    13. db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)

    1.4.8. Joins

    指定关联条件

    1. rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
    2. for rows.Next() {
    3. ...
    4. }
    5. db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
    6. // 多个关联查询
    7. db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)

    使用 Pluck 从模型中查询单个列作为集合。如果想查询多个列,应该使用 Scan 代替。

    1. var ages []int64
    2. db.Find(&users).Pluck("age", &ages)
    3. var names []string
    4. db.Model(&User{}).Pluck("name", &names)
    5. db.Table("deleted_users").Pluck("name", &names)
    6. db.Select("name, age").Find(&users)

    1.6. Scan