如何使用 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
}
我有一个 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
}