【问题标题】:Why does Go treat a Postgresql numeric & decimal columns as []uint8?为什么 Go 将 Postgresql 数字和十进制列视为 []uint8?
【发布时间】:2015-11-03 22:46:02
【问题描述】:

我不确定这是 Go 中的错误还是我不明白的问题。我有以下内容:

package main

import (
  "database/sql"
  "log"
  "reflect"

  _ "github.com/lib/pq"
)

func main() {
  Db, err := sql.Open("postgres", "user=yoitsme password=openupitsme host=x.x.x.x dbname=mydb")
  if err != nil {
    log.Println(err)
  }
  rows, err := Db.Query("SELECT 1.3250::numeric, 8.548::decimal, 908.234::float, 1234::integer")
  defer rows.Close()
  for rows.Next() {
    var col1, col2, col3, col4 interface{}
    if err := rows.Scan(&col1, &col2, &col3, &col4); err != nil {
      log.Println(err)
    }
    log.Println(col1, reflect.TypeOf(col1))
    log.Println(col2, reflect.TypeOf(col2))
    log.Println(col3, reflect.TypeOf(col3))
    log.Println(col4, reflect.TypeOf(col4))
  }
  if err = rows.Err(); err != nil {
    log.Println(err)
  }

}

打印出来:

2015/08/11 09:35:47 [49 46 51 50 53 48] []uint8
2015/08/11 09:35:47 [56 46 53 52 56] []uint8
2015/08/11 09:35:47 908.234 float64
2015/08/11 09:35:47 1234 int64

所以,对于实际上是数字的前两列,我得到 []uint8(例如字符串)。最后两列与预期一致。根据 Postgresql Numeric & Decimal types are part of the SQL standard。那么,为什么 Go 不遵循他们的 database/sql 包中的 SQL 标准呢?是因为 Go 没有内置的“十进制”类型吗?由于语言的缺陷,database/sql 包将数字变成了字符串似乎是错误的......

【问题讨论】:

  • 您没有任何字节切片...您的输出显示 []uint8 这是一个小的无符号整数。一个字节切片是[]byte。
  • @evanmcdonnal...啊,是的。谢谢!我已经更新了帖子。
  • @JimB 啊,我看到了[49 46 51 50 53 48] = "1.3250"。嗯,这是有道理的。

标签: postgresql go postgresql-9.4


【解决方案1】:

因为没有更好的解决方案。 (至少直到Go 1.5's big.Float)。还有什么其他选择?

  • 把它变成一个整数。显然是一个糟糕的解决方案,因为数字可以有小数部分。

  • 把它变成float64。这是邪恶。尤其是当您使用金钱时(numeric 和 decimal 等类型的使用率最高)。

这个特定的数据库驱动程序选择返回一个包含数字的字符串 - 让 您 决定是否丢失一些精度(通过将其转换为 float64 和 strconv)或使用一个十进制/精确数字库(如 gmp 或 math/big)。

【讨论】:

  • 将其转换为 Go 中一个缺点的字符串 b/c 似乎是一个糟糕的解决方案。
  • @kristen 我不会认为这是 Go 的缺点。这些更大/更高精度的数字类型都不是任何语言的原生类型。做出这个决定的是 Postgresql 驱动程序的作者。如果他们想做一些更明智的事情,他们可以在 Go 中提供几个类型来托管他们没有兼容原生的类型。
  • big.Float 是二进制浮点数,不适合表示具有固定十进制精度的数字。
  • 实际上,除非您使用二进制协议选项,否则 PostgreSQL 会将 numeric 和 decimal 作为在线文本发送。所以 Go 驱动程序并没有将 PostgreSQL 发送的内容转换为其他任何内容,因为没有合适的本地类型。它在这里做的是正确的事情,并且只有在 Go 获得本机任意精度十进制浮点数据类型时才应该做其他事情。
【解决方案2】:

以下是开发人员对该问题的答案的问题:https://github.com/lib/pq/issues/648

对小数使用 float64 类型是不安全的,因为浮点数不能代表所有小数。例如,小数支持比浮点数大得多的指数,并且浮点数的系数在转换为其基数 2 表示时会发生变化。在 go 中将字符串转换为浮点数是微不足道的,因此我们将保持这种行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-26
    • 2016-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 2022-08-09
    • 2011-02-09
    相关资源
    最近更新 更多