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

时间:2018-02-05 23:09:22

标签: postgresql go pq

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

difficulty          NUMERIC     NOT NULL,

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

此代码不起作用:

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 $1 type: unsupported type big.Int, a struct

3 个答案:

答案 0 :(得分:3)

首先,您应该对PostgreSQL使用数字占位符($1$2,...),因为它是本机使用的。至于将bignum放入数据库中的numeric列,快速浏览文档和源表明您最好的选择是使用字符串(PostgreSQL将其视为“未知”类型的值)然后让PostgreSQL解析它并根据列的(已知)类型进行转换。

这样的事情:

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

类似的方法适用于驱动程序本身无法理解的任何其他PostgreSQL类型;总会有一个字符串表示,你可以使用它来实现它。

您还可以type SQLBigInt big.Int并实施driver.Valuer的{​​{1}}界面:

database/sql/driver

然后可能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进行阅读,但这可能会变得很丑陋,可能不值得付出努力,因为无论如何你总是要打包和解包。

答案 1 :(得分:0)

您可以实现评估器和扫描仪界面

//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)
}

答案 2 :(得分:0)

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

示例使用:

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

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