【发布时间】:2015-02-21 06:20:56
【问题描述】:
我正在编写一个基本程序来从数据库表中读取值并在表中打印。桌子上有一个古老的程序。该行中的某些字段是可选的,当我尝试将它们作为字符串读取时,出现以下错误:
panic: sql: Scan error on column index 2: unsupported driver -> Scan pair: <nil> -> *string
在阅读其他类似问题的问题后,我想出了以下代码来处理 nil 值。该方法在实践中效果很好。我得到纯文本和空字符串的值,而不是 nil 值。
但是,我有两个担忧:
- 这看起来效率不高。我需要处理 25 多个这样的字段,这意味着我将它们中的每一个都读取为字节并转换为字符串。太多的函数调用和转换。两个结构来处理数据等等......
- 代码看起来很难看。它已经看起来很复杂,有 2 个字段,当我到 25+ 时变得不可读
我做错了吗?是否有更好/更清洁/高效/惯用的 golang 方式从数据库中读取值?
我很难相信像 Go 这样的现代语言不会优雅地处理数据库返回。
提前致谢!
代码 sn-p:
// DB read format
type udInfoBytes struct {
id []byte
state []byte
}
// output format
type udInfo struct {
id string
state string
}
func CToGoString(c []byte) string {
n := -1
for i, b := range c {
if b == 0 {
break
}
n = i
}
return string(c[:n+1])
}
func dbBytesToString(in udInfoBytes) udInfo {
var out udInfo
var s string
var t int
out.id = CToGoString(in.id)
out.state = stateName(in.state)
return out
}
func GetInfo(ud string) udInfo {
db := getFileHandle()
q := fmt.Sprintf("SELECT id,state FROM Mytable WHERE id='%s' ", ud)
rows, err := db.Query(q)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
ret := udInfo{}
r := udInfoBytes{}
for rows.Next() {
err := rows.Scan(&r.id, &r.state)
if err != nil {
log.Println(err)
}
break
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
ret = dbBytesToString(r)
defer db.Close()
return ret
}
编辑:
我想要类似下面的东西,我不必担心处理 NULL 并自动将它们读取为空字符串。
// output format
type udInfo struct {
id string
state string
}
func GetInfo(ud string) udInfo {
db := getFileHandle()
q := fmt.Sprintf("SELECT id,state FROM Mytable WHERE id='%s' ", ud)
rows, err := db.Query(q)
if err != nil {
log.Fatal(err)
}
defer rows.Close()
r := udInfo{}
for rows.Next() {
err := rows.Scan(&r.id, &r.state)
if err != nil {
log.Println(err)
}
break
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
defer db.Close()
return r
}
【问题讨论】:
-
感谢您的回复。我看到大多数解决方案都建议使用 sql.NullString 或数据库特定库。我希望有一些通用的东西可以在“database/sql”上运行。暂时我将使用 sql.NullString 解决方案,因为我必须通过 ODBC 连接到远程 sqlserver 数据库(我知道,很痛苦)。