本文汇总一些工程中使用到的查询数据表的代码示例。由于是代码片段,不一定保证完整。但其思想可以参考。
问题提出工程中经常要使用到数据表(工作多年,不可避免沦为了CRUD工具人),打交道最多的是查询,对于插入更新接触比较少,由于所涉及的数据表是生产环境的,所以不敢越雷池半步。
golang
的sql
包虽然没有包含数据库驱动,但在语言级别统一了接口,所以使用上还是有一定的便利之处。之前用golang写的一个内部工具,需要使用到mysql、oraclass="superseo">cle、sqlite3三种不同的数据库,就是看上golang的这个特点。
然而有时数据表字段实在太多了,而很多表的处理方法是一样的,如果均一一编写,则略显繁琐。本文综合一些资料,根据经验,汇总了几种查询数据表的方式。
func GetIntervalDetail_inner(sqldb *sql.DB, version string) (rets []conf.TestInfo) {
sqlstr := fmt.Sprintf("select * from TestTable a where a.version = '%v' order by a.ID", version)
// klog.Println("sqlstr: ", sqlstr)
results, err := sqldb.Query(sqlstr)
if err != nil {
klog.Printf("Query error: %s\n", err.Error())
return
}
for results.Next() {
var item1, item2, item3, item4, item5, item7, item9, item10 sql.NullString
var item6, item8 int
err := results.Scan(&item1, &item2, &item3, &item4, &item5,
&item6, &item7, &item8, &item9, &item10)
if err != nil {
klog.Println("scan error: ", err)
break
}
// item7 有空格,先去掉
item7.String = strings.TrimSpace(item7.String)
if item7.String == "" {
item7.String = "none"
}
var tmp conf.TestInfo
tmp.Version = item1.String
tmp.Code = item2.String
tmp.ID = item3.String
tmp.Code1 = item4.String
tmp.Code2 = item5.String
tmp.Length = item6
tmp.F1_CODE = item7.String
tmp.F1_length = item8
tmp.F2_CODE = item9.String
tmp.F2_length = item10.String
rets = append(rets, tmp)
}
return
}
即使用到结构体,其本质也没有发生变化
func GetSpecialFee_inner(sqldb *sql.DB, Version string) (rets []conf.MySpeedRate) {
sqlstr := fmt.Sprintf("select * from FoobarTable where Version=%v", Version)
// klog.Println("sqlstr: ", sqlstr)
results, err := sqldb.Query(sqlstr)
if err != nil {
klog.Printf("Query error: %s\n", err.Error())
return
}
for results.Next() {
var data conf.MySpeedRate
err := results.Scan(&data.Version, &data.Rate[0], &data.Rate[1],
&data.Rate[2], &data.Rate[3], &data.Rate[4], &data.Rate[5], &data.Rate[6], &data.Rate[7],
&data.Rate[8], &data.Rate[9], &data.Rate[10], &data.Rate[11], &data.Rate[12], &data.Rate[13],
&data.Rate[14], &data.Rate[15])
if err != nil {
klog.Println("scan error: ", err)
break
}
rets = append(rets, data)
}
return
}
方案二:泛化:结构体
func GetAllRowsPtr(sqldb *sql.DB, query string, strname interface{}) (*[]interface{}, error) {
result := make([]interface{}, 0)
rows, err := sqldb.Query(query)
if err != nil {
return &result, err
}
defer rows.Close()
s := reflect.ValueOf(strname).Elem()
leng := s.NumField()
scans := make([]interface{}, leng)
for i := 0; i < leng; i++ {
scans[i] = s.Field(i).Addr().Interface()
}
for rows.Next() {
err = rows.Scan(scans...)
if err != nil {
panic(err)
}
result = append(result, s.Interface())
}
return &result, nil
}
方案三:泛化:字符串数组
func GetAllRowsString(sqldb *sql.DB, query string) ([]string, error) {
rows, err := sqldb.Query(query)
if err != nil {
return []string{}, err
}
defer rows.Close()
var results []string
var tmp string
// 获取字段名称
tmp = ""
cols, _ := rows.Columns()
for i := range cols {
tmp += cols[i] + ","
}
results = append(results, tmp)
// 根据字段数量,指定查询scan的参数
values := make([]sql.RawBytes, len(cols))
scans := make([]interface{}, len(cols))
for i := range values {
scans[i] = &values[i]
}
for rows.Next() {
if err := rows.Scan(scans...); err != nil {
fmt.Println("Error")
return []string{}, err
}
// 组装,暂定以逗号隔开
tmp = ""
for j := range values {
tmp += string(values[j]) + ","
}
results = append(results, tmp)
}
return results, nil
}
小结
方案一是将数据表映射到结构体中,因此需要定义对应的结构体,但可以与数据表不一一对应,即根据sql语句只查询个别字段并赋值,如果不嫌麻烦,或者结构体随处需要使用,则可用此法。
方案二不需要定义结构体,实际使用的是接口,使用时需指定字段名称。实现代码中,如果查询的数据表字段和总字段不匹配,会提示panic: sql: expected 19 destination arguments in Scan, not 4
。
方案三在方案二基础上进行修改。会自动匹配查询sql的字段。最终组装成csv格式字符串数组。
不同方案均有优劣,按需使用即可。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)