无法使用golang在postgresql中插入/更新具有自定义类型的数据

zysjyyx4  于 2023-02-06  发布在  Go
关注(0)|答案(1)|浏览(241)

我正在尝试使用jackc/pgx在PostgreSQL中插入/更新数据到一个包含自定义类型列的表中。这是一个golan结构体编写的表类型:

// Added this struct as a Types in PSQL
type DayPriceModel struct {
    Date                time.Time `json:"date"`
    High                float32   `json:"high"`
    Low                 float32   `json:"low"`
    Open                float32   `json:"open"`
    Close               float32   `json:"close"`
}

// The 2 columns in my table
type SecuritiesPriceHistoryModel struct {
    Symbol  string          `json:"symbol"`
    History []DayPriceModel `json:"history"`
}

我已经写了下面的代码:

func insertToDB(data SecuritiesPriceHistoryModel) {
        DBConnection := config.DBConnection
        _, err := DBConnection.Exec(context.Background(), "INSERT INTO equity.securities_price_history (symbol) VALUES ($1)", data.Symbol, data.History)
    }

但我无法插入自定义数据类型(DayPriceModel)。
我得到了一个类似failed to encode args[1]: unable to encode的错误(错误很长,主要显示我的数据,所以我选择了主要部分。
如何将具有这种自定义数据类型的数据INSERT到PSQL中?
PS:使用jackc/pgx的实现是首选,但数据库/sql也可以

e0bqpujr

e0bqpujr1#

我对pgx不够熟悉,不知道如何设置对复合类型数组的支持,但是,正如注解中提到的,你可以实现driver.Valuer接口,并让它产生一个有效的文本,这也适用于你存储结构体切片的情况,你只需要声明一个命名切片,并让它实现赋值器,然后使用它来代替未命名切片。

// named slice type
type DayPriceModelList []DayPriceModel

// the syntax for array of composites literal looks like
// this: '{"(foo,123)", "(bar,987)"}'. So the implementation
// below must return the slice contents in that format.
func (l DayPriceModelList) Value() (driver.Value, error) {
    // nil slice? produce NULL
    if l == nil {
        return nil, nil
    }
    // empty slice? produce empty array
    if len(l) == 0 {
        return []byte{'{', '}'}, nil
    }

    out := []byte{'{'}
    for _, v := range l {
        // This assumes that the date field in the pg composite
        // type accepts the default time.Time format. If that is
        // not the case then you simply provide v.Date in such a
        // format which the composite's field understand, e.g.,
        // v.Date.Format("<layout that the pg composite understands>")
        x := fmt.Sprintf(`"(%s,%f,%f,%f,%f)",`,
            v.Date,
            v.High,
            v.Low,
            v.Open,
            v.Close)
        out = append(out, x...)
    }
    out[len(out)-1] = '}' // replace last "," with "}"
    return out, nil
}

在编写插入查询时,请确保在占位符之后添加显式强制转换,例如。

type SecuritiesPriceHistoryModel struct {
    Symbol  string            `json:"symbol"`
    History DayPriceModelList `json:"history"` // use the named slice type
}

// ...

_, err := db.Exec(ctx, `INSERT INTO equity.securities_price_history (
    symbol
    , history
) VALUES (
    $1
    , $2::my_composite_type[])
`, data.Symbol, data.History)

// replace my_composite_type with the name of the composite type in the database

注意#1:根据postgres中复合类型的确切定义,上面的例子可能会起作用,也可能不会起作用,如果不起作用,只需调整代码使其起作用。
注意#2:上面例子中的一般方法是有效的,但是它可能不是非常有效。如果你需要代码是高性能的,不要逐字使用例子。

相关问题