天天看點

Beego models之三使用SQL語句進行查詢構造查詢

使用SQL語句進行查詢

在實際生産中,各種業務邏輯,model不能很好的滿足需求,是以就可以使用原生的sql。當然,如果你對sql比較熟悉,你會發現orm有時候沒有原生sql來的靈活,下面介紹beego的原生sql。

  • 使用 Raw SQL 查詢,無需使用 ORM 表定義
  • 多資料庫,都可直接使用占位符号

    ?

    ,自動轉換,可以防止sql注入
  • 查詢時的參數,支援使用 Model Struct 和 Slice, Array
ids := []int{1, 2, 3}
p.Raw("SELECT name FROM user WHERE id IN (?, ?, ?)", ids)
           

建立一個 RawSeter

o := orm.NewOrm()
var r RawSeter
r = o.Raw("UPDATE user SET name = ? WHERE name = ?", "testing", "slene")
           

我們來看看源代碼接口定義:

type RawSeter interface {
    //execute sql and get result
    Exec() (sql.Result, error)
    //query data and map to container
    //for example:
    //  var name string
    //  var id int
    //  rs.QueryRow(&id,&name) // id==2 name=="slene"
    QueryRow(containers ...interface{}) error

    // query data rows and map to container
    //  var ids []int
    //  var names []int
    //  query = fmt.Sprintf("SELECT 'id','name' FROM %suser%s", Q, Q)
    //  num, err = dORM.Raw(query).QueryRows(&ids,&names) // ids=>{1,2},names=>{"nobody","slene"}
    QueryRows(containers ...interface{}) (int64, error)
    SetArgs(...interface{}) RawSeter
    // query data to []map[string]interface
    // see QuerySeter's Values
    Values(container *[]Params, cols ...string) (int64, error)
    // query data to [][]interface
    // see QuerySeter's ValuesList
    ValuesList(container *[]ParamsList, cols ...string) (int64, error)
    // query data to []interface
    // see QuerySeter's ValuesFlat
    ValuesFlat(container *ParamsList, cols ...string) (int64, error)
    // query all rows into map[string]interface with specify key and value column name.
    // keyCol = "name", valueCol = "value"
    // table data
    // name  | value
    // total | 100
    // found | 200
    // to map[string]interface{}{
    //  "total": 100,
    //  "found": 200,
    // }
    RowsToMap(result *Params, keyCol, valueCol string) (int64, error)
    // query all rows into struct with specify key and value column name.
    // keyCol = "name", valueCol = "value"
    // table data
    // name  | value
    // total | 100
    // found | 200
    // to struct {
    //  Total int
    //  Found int
    // }
    RowsToStruct(ptrStruct interface{}, keyCol, valueCol string) (int64, error)

    // return prepared raw statement for used in times.
    // for example:
    //  pre, err := dORM.Raw("INSERT INTO tag (name) VALUES (?)").Prepare()
    //  r, err := pre.Exec("name1") // INSERT INTO tag (name) VALUES (`name1`)
    Prepare() (RawPreparer, error)
}
           

下面具體介紹一下接口:

Exec

執行 sql 語句,傳回

sql.Result

對象

res, err := o.Raw("UPDATE user SET name = ?", "your").Exec()
if err == nil {
    num, _ := res.RowsAffected()
    fmt.Println("mysql row affected nums: ", num)
}
           

QueryRow

QueryRow 和 QueryRows 提供進階 sql mapper 功能

支援 struct

type User struct {
    Id       int
    UserName string
}

var user User
err := o.Raw("SELECT id, user_name FROM user WHERE id = ?", 1).QueryRow(&user)
           

QueryRows

QueryRows 支援的對象還有 map 規則是和 QueryRow 一樣的,但都是 slice

type User struct {
    Id       int
    UserName string
}

var users []User
num, err := o.Raw("SELECT id, user_name FROM user WHERE id = ?", 1).QueryRows(&users)
if err == nil {
    fmt.Println("user nums: ", num)
}
           

SetArgs

改變 Raw(sql, args…) 中的 args 參數,傳回一個新的 RawSeter

用于單條 sql 語句,重複利用,替換參數然後執行。

res, err := r.SetArgs("arg1", "arg2").Exec()
res, err := r.SetArgs("arg1", "arg2").Exec()
...
           

Values / ValuesList / ValuesFlat

Raw SQL 查詢獲得的結果集 Value 為

string

類型,NULL 字段的值為空 ``

from beego 1.1.0

Values, ValuesList, ValuesFlat 的參數,可以指定傳回哪些 Columns 的資料

通常情況下,是無需指定的,因為 sql 語句中你可以自行設定 SELECT 的字段

Values

傳回結果集的 key => value 值

var maps []orm.Params
num, err := o.Raw("SELECT user_name FROM user WHERE status = ?", 1).Values(&maps)
if err == nil && num > 0 {
    fmt.Println(maps[0]["user_name"]) // slene
}
           

ValuesList

傳回結果集 slice

var lists []orm.ParamsList
num, err := o.Raw("SELECT user_name FROM user WHERE status = ?", 1).ValuesList(&lists)
if err == nil && num > 0 {
    fmt.Println(lists[0][0]) // slene
}
           

ValuesFlat

傳回單一字段的平鋪 slice 資料

var list orm.ParamsList
num, err := o.Raw("SELECT id FROM user WHERE id < ?", 10).ValuesFlat(&list)
if err == nil && num > 0 {
    fmt.Println(list) // []{"1","2","3",...}
}
           

RowsToMap

SQL 查詢結果是這樣

name value
total 100
found 200

查詢結果比對到 map 裡

res := make(orm.Params)
nums, err := o.Raw("SELECT name, value FROM options_table").RowsToMap(&res, "name", "value")
// res is a map[string]interface{}{
//  "total": 100,
//  "found": 200,
// }
           

RowsToStruct

查詢結果比對到 struct 裡

type Options struct {
    Total int
    Found int
}

res := new(Options)
nums, err := o.Raw("SELECT name, value FROM options_table").RowsToStruct(res, "name", "value")
fmt.Println(res.Total) // 100
fmt.Println(res.Found) // 200
           
比對支援的名稱轉換為 snake -> camel, eg: SELECT user_name … 需要你的 struct 中定義有 UserName

Prepare

用于一次 prepare 多次 exec,以提高批量執行的速度。

p, err := o.Raw("UPDATE user SET name = ? WHERE name = ?").Prepare()
res, err := p.Exec("testing", "slene")
res, err  = p.Exec("testing", "astaxie")
...
...
p.Close() // 别忘記關閉 statement
           

構造查詢

QueryBuilder 提供了一個簡便,流暢的 SQL 查詢構造器。在不影響代碼可讀性的前提下用來快速的建立 SQL 語句。

QueryBuilder 在功能上與 ORM 重合, 但是各有利弊。ORM 更适用于簡單的 CRUD 操作,而 QueryBuilder 則更适用于複雜的查詢,例如查詢中包含子查詢和多重聯結。

使用方法:

// User 包裝了下面的查詢結果
type User struct {
    Name string
    Age  int
}
var users []User

// 擷取 QueryBuilder 對象. 需要指定資料庫驅動參數。
// 第二個傳回值是錯誤對象,在這裡略過
qb, _ := orm.NewQueryBuilder("mysql")

// 建構查詢對象
qb.Select("user.name",
    "profile.age").
    From("user").
    InnerJoin("profile").On("user.id_user = profile.fk_user").
    Where("age > ?").
    OrderBy("name").Desc().
    Limit(10).Offset(0)

// 導出 SQL 語句
sql := qb.String()

// 執行 SQL 語句
o := orm.NewOrm()
o.Raw(sql, 20).QueryRows(&users)
           

完整 API 接口:

// QueryBuilder is the Query builder interface
type QueryBuilder interface {
    Select(fields ...string) QueryBuilder
    ForUpdate() QueryBuilder
    From(tables ...string) QueryBuilder
    InnerJoin(table string) QueryBuilder
    LeftJoin(table string) QueryBuilder
    RightJoin(table string) QueryBuilder
    On(cond string) QueryBuilder
    Where(cond string) QueryBuilder
    And(cond string) QueryBuilder
    Or(cond string) QueryBuilder
    In(vals ...string) QueryBuilder
    OrderBy(fields ...string) QueryBuilder
    Asc() QueryBuilder
    Desc() QueryBuilder
    Limit(limit int) QueryBuilder
    Offset(offset int) QueryBuilder
    GroupBy(fields ...string) QueryBuilder
    Having(cond string) QueryBuilder
    Update(tables ...string) QueryBuilder
    Set(kv ...string) QueryBuilder
    Delete(tables ...string) QueryBuilder
    InsertInto(table string, fields ...string) QueryBuilder
    Values(vals ...string) QueryBuilder
    Subquery(sub string, alias string) string
    String() string
}