如何处理数据库中的nil返回值?

Flo*_*aja 10 database go

我正在编写一个基本程序来读取数据库表中的值并在表中打印.该表由一个古老的程序填充.行中的某些字段是可选的,当我尝试将它们作为字符串读取时,我收到以下错误:

panic: sql: Scan error on column index 2: unsupported driver -> Scan pair: <nil> -> *string
Run Code Online (Sandbox Code Playgroud)

在我阅读了类似问题的其他问题之后,我想出了以下代码来处理nil值.该方法在实践中工作正常.我以纯文本和空字符串而不是nil值获取值.

但是,我有两个问题:

  1. 这看起来效率不高.我需要处理25个这样的字段,这意味着我将每个字段作为字节读取并转换为字符串.函数调用和转换太多.两个结构来处理数据等等......
  2. 代码看起来很难看.它已经看起来很复杂的2个领域,并且变得不可读,因为我去了25+

我做错了吗?是否有更好/更清洁/高效/惯用的golang方式从数据库中读取值?

我发现很难相信像Go这样的现代语言不会优雅地处理数据库.

提前致谢!

代码段:

// 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
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我希望有类似下面的内容,我不必担心处理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
}
Run Code Online (Sandbox Code Playgroud)

tmi*_*hel 21

有不同的类型来处理null从数据库如未来值sql.NullBool,sql.NullFloat64等等.

例如:

 var s sql.NullString
 err := db.QueryRow("SELECT name FROM foo WHERE id=?", id).Scan(&s)
 ...
 if s.Valid {
    // use s.String
 } else {
    // NULL value
 }
Run Code Online (Sandbox Code Playgroud)


mat*_*ttn 8

go的数据库/ sql包处理类型的指针.

package main

import (
    "database/sql"
    "fmt"
    _ "github.com/mattn/go-sqlite3"
    "log"
)

func main() {
    db, err := sql.Open("sqlite3", ":memory:")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    _, err = db.Exec("create table foo(id integer primary key, value text)")
    if err != nil {
        log.Fatal(err)
    }
    _, err = db.Exec("insert into foo(value) values(null)")
    if err != nil {
        log.Fatal(err)
    }
    _, err = db.Exec("insert into foo(value) values('bar')")
    if err != nil {
        log.Fatal(err)
    }
    rows, err := db.Query("select id, value from foo")
    if err != nil {
        log.Fatal(err)
    }
    for rows.Next() {
        var id int
        var value *string
        err = rows.Scan(&id, &value)
        if err != nil {
            log.Fatal(err)
        }
        if value != nil {
            fmt.Println(id, *value)
        } else {
            fmt.Println(id, value)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

你应该得到如下:

1 <nil>
2 bar
Run Code Online (Sandbox Code Playgroud)