我正在使用尚未规范化的数据库,此表包含超过40列的记录。
以下是我的Go代码(尝试)将记录扫描到一个大型结构中:
type Coderyte struct {
ID int `json:"id"`
EmrID int `json:"emr_id"`
DftID int `json:"dft_id"`
Fix int `json:"fix"`
ReportDate string `json:"report_date"` // Time?
Patient string `json:"patient"`
... // etc
}
func ReadCoderyte(res http.ResponseWriter, req *http.Request) {
rows, err := db.Query("SELECT * FROM coderyte")
if err != nil {
http.Error(res, "Error querying database", 500)
}
defer rows.Close()
// Convert rows into a slice of Coderyte structs
coderytes := make([]*Coderyte, 0)
for rows.Next() {
coderyte := new(Coderyte)
err := rows.Scan(&coderyte) // Expected 42 columns
if err != nil {
panic(err)
http.Error(res, "Error converting coderyte object", 500)
}
coderytes = append(coderytes, coderyte)
}
当我调用此代码时,Scan
抱怨它“预期有42个目标参数,而不是1”。我的理解是,我需要在扫描调用内部解决这个大结构中的每个字段,即Scan(&coderyte.ID, &coderyte.EmrID, etc)
我的搜索结果只产生了this other question,其中建议的答案是使用sqlx
。如果我不需要它,我试图避免使用第三方工具。
我的问题归结为:有没有办法将大型数据库记录转换为结构而不指定每个字段?。
我还应该注意,这个函数的最终目标是返回一个JSON对象数组,但是我没有包含那部分代码,因为我觉得它并不重要。如果有办法绕过Scan
并返回JSON,那么这也是一个值得赞赏的答案。
答案 0 :(得分:2)
此函数的最终目标是返回JSON对象数组
听起来你完全可以通过结构,然后扫描到map[string]interface{}
,并且动态地完成所有操作:
你可以这样做:
rows, _ := db.Query("SELECT * FROM coderyte")
cols, _ := rows.Columns()
store := []map[string]interface{}
for rows.Next() {
columns := make([]interface{}, len(cols))
columnPointers := make([]interface{}, len(cols))
for i, _ := range columns {
columnPointers[i] = &columns[i]
}
if err := rows.Scan(columnPointers...); err != nil {
return err
}
m := make(map[string]interface{})
for i, colName := range cols {
val := columnPointers[i].(*interface{})
m[colName] = *val
}
store = append(store, m)
}
js, _ := json.Marshal(store)
fmt.Println(string(js))
现在,显然你也可以将它转换为结构,因为你可以使用json并执行json.Unmarshal
,但是考虑到你的用例似乎是一个毫无意义的额外步骤。
js, _ := json.Marshal(store)
structs := []Coderyte{}
json.Unmarshal(js, &structs)
所有这一切,你应该只使用sqlx - 它们可能做得更聪明,并且更有效率。