如何使用 lib/pq 驱动程序插入 NUMERIC 字段类型?

How to insert NUMERIC field type using lib/pq driver?

我有一个 table,其中有一个字段存储了一个非常大的数字(math.big,它比 uint64 大)。我将其存储为 DECIMAL 类型:

difficulty          NUMERIC     NOT NULL,

那么,如何使用 PQ 库 (github.com/lib/pq) 从 Go 代码中插入该字段?

此代码无效:

me@desk:~/src/github.com/myapp/misc$ cat insertbig.go
package main

import (
    "database/sql"
    _ "github.com/lib/pq"
    "os"
    "log"
    "math/big"
)
func main() {
    var err error
    var db *sql.DB
    std_out:=log.New(os.Stdout,"",0)

    conn_str:="user='testuser' dbname='testdb' password='testpasswd'";
    db,err=sql.Open("postgres",conn_str);
    if (err!=nil) {
        log.Fatal(err);
    }
    _,err=db.Exec("CREATE TABLE bigtable(difficulty NUMERIC)");

    difficulty:=big.NewInt(0);
    difficulty.SetString("1111111111111111111111111111111111111111111111111111111111111111111111",10);
    _,err=db.Exec("INSERT INTO bigtable(difficulty) VALUES(?)",difficulty);
    if (err!=nil) {
        log.Fatal(err);
    } else {
        std_out.Println("record was inserted");
    }
}

me@desk:~/src/github.com/myapp/misc$ 

它给我这个错误:

2018/02/05 17:00:25 sql: converting argument  type: unsupported type big.Int, a struct

首先,您应该在 PostgreSQL 中使用数字占位符(</code>、<code>、...),因为它本身就是这样使用的。至于将 bignum 放入数据库中的 numeric 列,通过文档和源快速 运行 建议您最好的选择是使用字符串(PostgreSQL 会将其视为类型的值"unknown") 并让 PostgreSQL 解析它并根据列的(已知)类型对其进行转换。

所以像这样:

difficulty := "1111111111111111111111111111111111111111111111111111111111111111111111"
_, err = db.Exec("INSERT INTO bigtable (difficulty) VALUES ()", difficulty)

类似的方法适用于驱动程序本身不理解的任何其他 PostgreSQL 类型;总会有一个字符串表示形式供您使用。


您还可以 type SQLBigInt big.Int 并从 database/sql/driver:

实现 driver.Valuer 接口
type SQLBigInt big.Int
func (i *SQLBigInt) Value() (driver.Value, error) {
    return (*big.Int)(i).String(), nil
}

// Or
type SQLBigInt struct {
    big.Int
}
func (i *SQLBigInt) Value() (driver.Value, error) {
    return i.String(), nil
}

然后可能 sql.Scanner 来自 "database/sql" 用于阅读,但这可能会变得丑陋并且可能不值得付出努力,因为无论如何你都会一直包装和展开。

您可以实现估价器和扫描器接口

//BigInt big.Int alias
   type BigInt struct {
      big.Int
   }

// Value implements the Valuer interface for BigInt
func (b *BigInt) Value() (driver.Value, error) {
   if b != nil {
      return b.String(), nil
   }
   return nil, nil
}

// Scan implements the Scanner interface for BigInt
func (b *BigInt) Scan(value interface{}) error {
    var i sql.NullString
    if err := i.Scan(value); err != nil {
        return err
    }
    if _, ok := b.SetString(i.String, 10); ok {
       return nil
    }
    return fmt.Errorf("Could not scan type %T into BigInt", value)
}

我遇到了类似的问题并尝试构建 this 包:

使用示例:

import (
    "github.com/d-fal/bigint"
)

    type TableWithBigint struct {
        Id        uint64
        Name      string
        Deposit   *bigint.Bigint
    }