为了账号安全,请及时绑定邮箱和手机立即绑定

插入 postgresql 十进制字段失败,出现错误“无法将 {125.00} 转换为 Int2”

插入 postgresql 十进制字段失败,出现错误“无法将 {125.00} 转换为 Int2”

Go
LEATH 2023-01-03 15:36:01
我对 golang 很陌生。我正在尝试使用网络应用程序 gin-gonic 插入到具有数字字段的 postgresql 表中。postgres=# \d user_txns;                       Table "public.user_txns"   Column    |         Type          | Collation | Nullable | Default-------------+-----------------------+-----------+----------+--------- user_id     | character varying(15) |           | not null | txn_code    | smallint              |           | not null | description | character varying(64) |           | not null | txn_amount  | numeric(15,4)         |           | not null | txn_type    | smallint              |           | not null | voucher     | character varying(16) |           |          |我正在使用 jackc pgxpool 插入到表中,如下所示。109 ▏ sql := `INSERT INTO user_txns VALUES ($1,$2, $3, $4, $5)`▎ 110 ▏ _, err = tx.Exec(context.Background(), sql,▎ 111 ▏ ▏ ▏ ▏ ▏ ▏ claims["phone"],▎ 112 ▏ ▏ ▏ ▏ ▏ ▏ recharge,▎ 113 ▏ ▏ ▏ ▏ ▏ ▏ "User recharge",▎ 114 ▏ ▏ ▏ ▏ ▏ ▏ recharge.Amount,▎ 115 ▏ ▏ ▏ ▏ ▏ ▏ credit,▎ 116 ▏ )▎ 117 ▏ if err != nil {▎ 118 ▏ ▏ c.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})▎ 119 ▏ ▏ return▎ 120 ▏ },有效负载是具有以下结构的 json 请求:{  "amount": 125.00 }我将请求解组为如下定义的结构。type Recharge struct {  Amount string `json:"amount" binding:"required"`}插入失败并出现错误"msg": "无法将 {125} 转换为 Int2"用于插入小数字段的正确 golang 数据类型是什么?谢谢
查看完整描述

1 回答

?
潇潇雨雨

TA贡献1833条经验 获得超4个赞

125.00向postgres 类型的列中插入一个值的最简单方法是numeric在 Go 中使用 float 类型。这是开箱即用的,因此无需实现任何类型的自定义接口。


例如:


CREATE TABLE t (

    id serial PRIMARY KEY

    , amount numeric(15,4) NOT NULL

    -- ...

);

data := []byte(`{"amount": 125.00}`)

var obj struct {

    Amount float64 `json:"amount"`

}

if err := json.Unmarshal(data, &obj); err != nil {

    panic(err)

}


_, err := db.Exec(`INSERT INTO t (amount) VALUES ($1)`, obj.Amount)

然而,浮点类型容易出现舍入误差,因此存储货币金额的常见做法是使用整数来表示以分为单位的值。例如125.00变成12500。这也开箱即用。


例如:


CREATE TABLE t (

    id serial PRIMARY KEY

    , amount int8 NOT NULL

    -- ...

);

data := []byte(`{"amount": 12500}`)

var obj struct {

    Amount int64 `json:"amount"`

}

if err := json.Unmarshal(data, &obj); err != nil {

    panic(err)

}


_, err := db.Exec(`INSERT INTO t (amount) VALUES ($1)`, obj.Amount)

如果您想使用pgtype.Numeric来存储和检索数据库中的金额,那么您将不得不做一些额外的工作,因为pgtype.Numeric不知道如何编码/解码 JSON 125.00/"125.00"值。


您可以做的一件事是声明一个自定义结构类型,让它嵌入该pgtype.Numeric类型,然后让自定义结构类型实现json.Marshaler和json.Unmarshaler接口。


例如:


CREATE TABLE t (

    id serial PRIMARY KEY

    , amount numeric(15,4) NOT NULL

    -- ...

);

type MyNumeric struct {

    pgtype.Numeric

}


func (n *MyNumeric) UnmarshalJSON(data []byte) error {

    var s json.Number

    if err := json.Unmarshal(data, &s); err != nil {

        return err

    }

    return n.Numeric.Set(s.String())

}


func (n MyNumeric) MarshalJSON() ([]byte, error) {

    var f float64

    if err := n.Numeric.AssignTo(&f); err != nil {

        return nil, err

    }

    return []byte(strconv.FormatFloat(f, 'f', -1, 64)), nil

}

data := []byte(`{"amount": 125.00}`)

var obj struct {

    Amount MyNumeric `json:"amount"`

}

if err := json.Unmarshal(data, &obj); err != nil {

    panic(err)

}


_, err := db.Exec(`INSERT INTO t (amount) VALUES ($1)`, obj.Amount)


查看完整回答
反对 回复 2023-01-03
  • 1 回答
  • 0 关注
  • 86 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信