查询v2

1. 检索单个对象

GORM 提供了 FirstTakeLast 方法,以便从数据库中检索单个对象。当查询数据库时它添加了 LIMIT 1 条件,且没有找到记录时,它会返回 ErrRecordNotFound 错误

func QueryTest1(db *gorm.DB) {
    // 获取第一条记录(主键升序)
    user1 := User{}
    db.First(&user1)
    fmt.Println(user1)

    // 获取一条记录,没有指定排序字段
    user2 := User{}
    db.Take(&user2)
    fmt.Println(user2)

    // 获取最后一条记录(主键降序)
    user3 := User{}
    db.Last(&user3)
    fmt.Println(user3)

    result := db.First(&user1)
    fmt.Println(result.RowsAffected) // 返回找到的记录数
    fmt.Println(result.Error)        // returns error
    // 检查 ErrRecordNotFound 错误
    errors.Is(result.Error, gorm.ErrRecordNotFound)
}

image-20220627212919667

FirstLast 方法会根据主键查找到第一个、最后一个记录, 它仅在通过 struct 或提供 model 值进行查询时才起作用。 如果 model 类型没有定义主键,则按第一个字段排序,例如:

func QueryTest2(db *gorm.DB) {
    // 可以
    var user User
    db.First(&user)
    fmt.Println(user)
    fmt.Println()

    // 可以
    result := map[string]interface{}{}
    db.Model(&User{}).First(result)
    fmt.Println(result)
    fmt.Println()

    // 不行
    result2 := map[string]interface{}{}
    db.Table("user").First(result2)
    fmt.Println(result2)
    fmt.Println()

    // 但可以配合 Take 使用
    result3 := map[string]interface{}{}
    db.Table("user").Take(result3)
    fmt.Println(result3)
    fmt.Println()

    // 根据第一个字段排序
    result4 := db.First(&User{})
    fmt.Println(result4.RowsAffected)
}

image-20220627212857847

1.1. 根据主键检索

您可以使用 内联条件 来检索对象。 传入字符串参数时注意避免 SQL 注入问题,查看 安全 获取详情

func QueryTest3(db *gorm.DB) {
    user := User{}
    db.First(&user, 10)
    fmt.Println(user)
    fmt.Println()

    user2 := User{}
    db.First(&user2, "10")
    fmt.Println(user2)
    fmt.Println()

    users := []User{
        {},
    }
    db.Find(&users, []int{1, 2, 3})
    for _, user := range users {
        fmt.Println(user)
    }
    fmt.Println()

}

image-20220627212838553

2. 检索全部对象

// QueryALlTest ## 检索全部对象
func QueryALlTest(db *gorm.DB) {
    users := []User{
        {},
    }
    result := db.Find(&users)
    for _, user := range users {
        fmt.Println(user)
    }
    fmt.Println(result.RowsAffected)
    fmt.Println(result.Error)

}

image-20220627212805850

3. 条件

3.1. String 条件

func FilterTest(db *gorm.DB) {
    // 获取第一条匹配的记录
    var user User
    db.Where("name = ?", "ee").First(&user)
    fmt.Println(user)

    // 获取全部匹配的记录
    users := []User{
        {},
    }
    result := db.Where("name = ?", "zs").Find(&users)
    fmt.Println(result.RowsAffected)

    // IN
    users = []User{
        {},
    }
    result2 := db.Where("name IN ?", []string{"zs", "aa"}).Find(&users)
    fmt.Println(result2.RowsAffected)

    // LIKE
    users = []User{
        {},
    }
    result3 := db.Where("name like ?", "%z%").Find(&users)
    fmt.Println(result3.RowsAffected)

    // AND
    users = []User{
        {},
    }
    result4 := db.Where("name = ? AND age >= ?", "zs", 18).Find(&users)
    fmt.Println(result4.RowsAffected)

    // Time
    users = []User{
        {},
    }
    result5 := db.Where("updated_at > ?", "2022-06-21 00:00:00").Find(&users)
    fmt.Println(result5.RowsAffected)

    // BETWEEN
    users = []User{
        {},
    }
    result6 := db.Where("created_at BETWEEN ? AND ?", "2022-06-20 00:00:00", "2022-06-21 00:00:00").Find(&users)
    fmt.Println(result6.RowsAffected)
}

image-20220627212724369

3.2. Struct & Map 条件

func FilterMapAndStruct(db *gorm.DB) {
    //Struct
    var user User
    db.Where(&User{Name: "zs", Age: 18}).First(&user)
    fmt.Println(user)

    // Map
    users := []User{
        {},
    }
    db.Where(map[string]interface{}{"name": "ls", "age": 22}).Find(&users)
    fmt.Println(users)

    // 主键切片条件
    users = []User{
        {},
    }
    db.Where([]int{1, 3, 5}).Find(&users)
    fmt.Println("主键切片条件", users)

}

image-20220627212547325

注意 当使用结构作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0''false 或其他 零值,该字段不会被用于构建查询条件,例如:

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;

3.3. 内联条件

用法与 Where 类似

func FilterTest2(db *gorm.DB) {
    // 根据主键获取记录,如果是非整型主键
    var user User
    db.First(&user, "id = ?", "5")
    fmt.Println(1, user)

    // Plain SQL
    user = User{}
    db.Find(&user, "name = ?", "zs")
    fmt.Println(2, user)

    users := []User{
        {},
    }
    db.Find(&users, "name <> ? AND age > ?", "zs", 20)
    fmt.Println(3, users)

    // Struct
    users = []User{
        {},
    }
    db.Find(&users, User{Age: 22})
    fmt.Println(4, users)

    // Map
    users = []User{
        {},
    }
    db.Find(&users, map[string]interface{}{"age": 20})
    fmt.Println(5, users)

}

image-20220627212523290

3.4. Not 条件

构建 NOT 条件,用法与 Where 类似

func FilterNot(db *gorm.DB) {
    var user User
    db.Not("name = ?", "zs").First(&user)
    fmt.Println(1, user)

    // Not In
    users := []User{
        {},
    }
    db.Not(map[string]interface{}{"name": []string{"zs", "ls"}}).Find(&users)
    fmt.Println(2, users)

    // Struct
    user = User{}
    db.Not(User{Name: "zs", Age: 18}).First(&user)
    fmt.Println(3, user)

    // 不在主键切片中的记录
    user = User{}
    db.Not([]int{1, 2, 3}).First(&user)
    fmt.Println(4, user)

}

image-20220627212448715

3.5. Or 条件

func FilterOr(db *gorm.DB) {
    users := []User{
        {},
    }
    db.Where("name = ?", "zs").Or("name = ?", "ls").Find(&users)
    fmt.Println(1, users)

    // Struct
    users = []User{
        {},
    }
    db.Where("name = 'zs'").Or(User{Name: "ls", Age: 22}).Find(&users)
    fmt.Println(2, users)

    // Map
    users = []User{
        {},
    }
    db.Where("name = ?", "zs").Or(map[string]interface{}{"name": "ls", "age": 22}).Find(&users)
    fmt.Println(3, users)

}

image-20220627213828024

您还可以查看高级查询中的 分组条件,它被用于编写复杂 SQL

4. 选择特定字段

选择您想从数据库中检索的字段,默认情况下会选择全部字段

func SelectField(db *gorm.DB) {
    users := []User{
        {},
    }
    db.Select("name", "age").Find(&users)

    users = []User{
        {},
    }
    db.Select([]string{"name", "age"}).Find(&users)

    users = []User{
        {},
    }
    db.Table("user").Select("COALESCE(age,?)", 21).Rows()
}

image-20220627215821406

还可以看一看 智能选择字段

5. Order

指定从数据库检索记录时的排序方式

func OrderData(db *gorm.DB) {
    users := []User{
        {},
    }
    db.Order("age desc, name").Find(&users)

    // 多个 order
    users = []User{
        {},
    }
    db.Order("age desc").Order("name").Find(&users)

    users = []User{
        {},
    }
    db.Clauses(clause.OrderBy{
        Expression: clause.Expr{SQL: "FIELD(id,?)", Vars: []interface{}{[]int{1, 2, 3}},
            WithoutParentheses: true},
    }).Find(&users)
}

image-20220627220716891

6. Limit & Offset

Limit 指定获取记录的最大数量 Offset 指定在开始返回记录之前要跳过的记录数量

func LimitAndOffset(db *gorm.DB) {
    users := []User{
        {},
    }
    db.Limit(3).Find(&users)
    fmt.Println(1, users)

    users = []User{
        {},
    }
    users2 := []User{
        {},
    }
    db.Limit(1).Find(&users).Limit(-1).Find(&users2)
    fmt.Println(2, users)
    fmt.Println(3, users2)

    users = []User{
        {},
    }
    db.Limit(5).Offset(3).Find(&users)
    fmt.Println(4, users)

    // 作者测试 Offset 必须配合 Limit 否则报错
    //users = []User{
    //    {},
    //}
    //db.Offset(10).Find(&users).Offset(-1).Find(&user)
}

查看 Pagination 学习如何写一个分页器

image-20220628213917883

7. Group & Having

func GroupAndHaving(db *gorm.DB) {
    users := []User{
        {},
    }
    db.Model(&User{}).Select("name, sum(age) as total").Where(
        "name LIKE ?", "%z%").Group("name").Find(&users)
    fmt.Println(users)

    users = []User{
        {},
    }
    db.Model(&User{}).Select("name, sum(age) as total").Group(
        "name").Having("name = ?", "zs").First(&users)
    fmt.Println(users)

    /*
        rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
        for rows.Next() {
          ...
        }

        rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
        for rows.Next() {
          ...
        }

        type Result struct {
          Date  time.Time
          Total int64
        }
        db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)
    */
}

image-20220628215416129

8. Distinct

从模型中选择不相同的值

func DistinctData(db *gorm.DB) {
    users := []User{
        {},
    }
    db.Distinct("name", "age").Order("name, age desc").Find(&users)
}

Distinct 也可以配合 Pluck, Count 使用

image-20220628215734811

9. Joins

指定 Joins 条件

func JoinsModel(db *gorm.DB) {
    type Result struct {
        Name  string
        Name2 string
    }
    result := Result{}
    db.Model(&User{}).Select("user.name, user_infos.name").Joins(
        "left join user_infos on user_infos.name = user.name").Scan(&result)
    fmt.Println(result)

    /*
        rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
        for rows.Next() {
          ...
        }

        db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)

        // 带参数的多表连接
        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)
    */
}

image-20220628221201529

9.1. Joins 预加载

您可以使用 Joins 实现单条 SQL 预加载关联记录,例如:

func JoinsData(db *gorm.DB) {
    userInfos := []UserInfo{
        {},
    }
    db.Joins("CreditCard").Find(&userInfos)
}

参考 预加载 了解详情

image-20220628221439854

10. Scan

Scan 结果至 struct,用法与 Find 类似

func ScanData(db *gorm.DB) {
    type Result struct {
        Name string
        Age  int
    }
    result := Result{}
    db.Table("user").Select("name", "age").Scan(&result)
    fmt.Println(result)

    db.Raw("select name, age from user where name = ?", "ls").Scan(&result)
    fmt.Println(result)
}

image-20220628221835713

results matching ""

    No results matching ""