最近在用gorm查詢知足某個條件的全部記錄中最新的記錄,代碼可參考下面的例子,具體查詢語句以下所示,目的是查詢知足條件host_id=1的全部記錄中按時間倒序,而後返回最新的記錄。git
orm.First(&hostStat, "host_id = ?", 1).Order("time desc").Error
複製代碼
完整的casegithub
package main
import (
"os"
log "github.com/Sirupsen/logrus"
"github.com/jinzhu/gorm"
_ "github.com/mattn/go-sqlite3"
"time"
)
type HostStat struct {
Id int
HostId int
Message string
Time time.Time
}
func main() {
if _,err:=os.Stat("test.db");err==nil{
os.Remove("test.db")
}
orm, err := gorm.Open("sqlite3", "test.db")
if err != nil {
log.Errorf("gorm open err:%s", err)
return
}
orm.AutoMigrate(&HostStat{})
orm.Save(&HostStat{
HostId: 1,
Message: "first",
Time: time.Now(),
})
time.Sleep(1 * time.Second)
orm.Save(&HostStat{
HostId: 1,
Message: "second",
Time: time.Now(),
})
var hostStatList []HostStat
if err := orm.Find(&hostStatList).Error; err != nil {
log.Errorf("gorm find host stat list error:%s", err)
return
}
for _,host:=range hostStatList{
log.Println(host)
}
var hostStat HostStat
if err := orm.First(&hostStat, "host_id = ?", 1).Order("time desc").Error; err != nil {
log.Errorf("gorm get hostStat err:%s", err)
return
}
log.Println(hostStat.Message)
}
複製代碼
執行結果,從執行結果中發現,返回了第一條記錄,顯然不是想要的結果,預期返回的應該是第二條記錄,而實際返回的是第一條記錄。sql
INFO[0001] {1 1 first 2020-02-25 11:55:35.855536 +0800 +0800}
INFO[0001] {2 1 second 2020-02-25 11:55:36.860022 +0800 +0800}
INFO[0001] first
複製代碼
首先須要分析一下,爲何先first,在order會致使直接返回第一條記錄,在下面的代碼中,我打開的gorm的debug,並將order和first的順序換了一下,作對比。bash
if err := orm.Debug().First(&hostStat, "host_id = ?", 1).Order("time desc").Error; err != nil {
log.Errorf("gorm get hostStat err:%s", err)
return
}
log.Println(hostStat.Message)
if err := orm.Debug().Order("time desc").Find(&hostStat, "host_id = ?", 1).Limit(1).Error; err != nil {
log.Errorf("gorm get hostStat err:%s", err)
return
}
log.Println(hostStat.Message)
複製代碼
輸出結果顯示兩種作法都返回了第一條記錄,從debug信息裏看到ui
$ go run main.go
INFO[0001] {1 1 first 2020-02-25 15:38:30.467259 +0800 +0800}
INFO[0001] {2 1 second 2020-02-25 15:38:31.470624 +0800 +0800}
(/Users/zhangyi/go/src/goscripts/gorm/main.go:52)
[2020-02-25 15:38:31] [0.34ms] SELECT * FROM "host_stats" WHERE (host_id = '1') ORDER BY "host_stats"."id" ASC LIMIT 1
INFO[0001] first
(/Users/zhangyi/go/src/goscripts/gorm/main.go:58)
[2020-02-25 15:38:31] [0.26ms] SELECT * FROM "host_stats" WHERE ("id" = '1') AND ((host_id = '1')) ORDER BY time desc
INFO[0001] first
複製代碼
對於這種問題最好的解決方案就是手動拼寫sql,使用gorm.Raw(),下面給出了兩種對比的作法。spa
if err := orm.Debug().First(&hostStat, "host_id = ?", 1).Order("time desc").Error; err != nil {
log.Errorf("gorm get hostStat err:%s", err)
return
}
log.Println(hostStat.Message)
if err := orm.Debug().Raw("select * from host_stats where host_id = ? order by time desc limit 1", 1).Scan(&hostStat).Error; err != nil {
log.Errorf("gorm get hostStat err:%s", err)
return
}
log.Println(hostStat.Message)
複製代碼
輸出結果以下所示,從結果中能夠看出使用Raw方法的sql語句和結果符合預期。debug
$ go run main.go
INFO[0001] {1 1 first 2020-02-25 15:48:17.075904 +0800 +0800}
INFO[0001] {2 1 second 2020-02-25 15:48:18.076935 +0800 +0800}
(/Users/zhangyi/go/src/goscripts/gorm/main.go:52)
[2020-02-25 15:48:18] [0.33ms] SELECT * FROM "host_stats" WHERE (host_id = '1') ORDER BY "host_stats"."id" ASC LIMIT 1
INFO[0001] first
(/Users/zhangyi/go/src/goscripts/gorm/main.go:58)
[2020-02-25 15:48:18] [0.27ms] select * from host_stats where host_id = '1' order by time desc limit 1
INFO[0001] second
複製代碼