使用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
}