繁体   English   中英

如何在 Go 中表示 PostgreSQL 区间

[英]How to represent PostgreSQL interval in Go

如何在 Go 中表示 PostgreSQL 区间?

我的结构如下所示:

type Product struct {
    Id              int
    Name            string
    Type            int
    Price           float64
    Execution_time  ????
}

我数据库上的 execution_time 字段是interval

最佳答案我已经遇到是使用bigint在您的架构,并实现ValueScan上的包装类型time.Duration

// Duration lets us convert between a bigint in Postgres and time.Duration
// in Go
type Duration time.Duration

// Value converts Duration to a primitive value ready to written to a database.
func (d Duration) Value() (driver.Value, error) {
    return driver.Value(int64(d)), nil
}

// Scan reads a Duration value from database driver type.
func (d *Duration) Scan(raw interface{}) error {
    switch v := raw.(type) {
    case int64:
        *d = Duration(v)
    case nil:
        *d = Duration(0)
    default:
        return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v", v)
    }
    return nil
}

不幸的是,你会牺牲在查询中进行区间运算的能力 - 除非一些聪明的家伙想要发布bigint => interval的类型转换。

如果你确定有符合time.Duration限制,你只需要秒精度你可以:

  • 创建具有SECOND精度的表... someInterval INTERVAL SECOND(0), ...
  • 将INTERVAL转换为秒: SELECT EXTRACT(EPOCH FROM someInterval) FROM someTable;

  • 使用time.Duration :: Seconds将数据插入到准备语句中

一种解决方案是将time.Duration类型包装在包装器类型中,并在其上提供sql.Scannerdriver.Valuer的实现。

// PgDuration wraps a time.Duration to provide implementations of
// sql.Scanner and driver.Valuer for reading/writing from/to a DB.
type PgDuration time.Duration

Postgres 在插入INTERVAL列时提供的格式似乎非常灵活。 接受在持续时间上调用String()返回的默认格式,因此对于driver.Value的实现,只需调用它:

// Value converts the PgDuration into a string.
func (d PgDuration) Value() (driver.Value, error) {
    return time.Duration(d).String(), nil
}

从 Postgres 检索INTERVAL值时,它以 Go 不易解析的格式返回它(例如"2 days 05:00:30.000250" ),因此我们需要在sql.Scanner的实现中进行一些手动解析sql.Scanner 就我而言,我只关心支持小时、分钟和秒,所以我实现如下:

// Scan converts the received string in the format hh:mm:ss into a PgDuration.
func (d *PgDuration) Scan(value interface{}) error {
    switch v := value.(type) {
    case string:
        // Convert format of hh:mm:ss into format parseable by time.ParseDuration()
        v = strings.Replace(v, ":", "h", 1)
        v = strings.Replace(v, ":", "m", 1)
        v += "s"
        dur, err := time.ParseDuration(v)
        if err != nil {
            return err
        }
        *d = PgDuration(dur)
        return nil
    default:
        return fmt.Errorf("cannot sql.Scan() PgDuration from: %#v", v)
    }
}

如果您需要支持其他持续时间单位,您可以从类似的方法开始,并适当地处理额外的单位。

此外,如果您碰巧使用 GORM 库来自动迁移表,您还需要提供 GORM 的migrator.GormDataTypeInterface的实现:

// GormDataType tells GORM to use the INTERVAL data type for a PgDuration column.
func (PgDuration) GormDataType() string {
    return "INTERVAL"
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM