在golang中扫描SQL NULL值

时间:2017-06-21 08:03:03

标签: sql json go

使用标准数据库/ sql Row.Scan()我在行中遇到空值问题。如果不考虑连续可能的空值,我可能会得到像<nil> -> *string这样的扫描错误。这很常见,使用LEFT JOIN查询或缺少NO NULL列约束的弱定义表。

sql.NullXXX种类型(例如sql.NullInt64)可用于扫描行中可能的空值,然后检查值是否为.Valid。但是,这些类型不实现JSON编组,需要更多的逻辑和编码。

要解决这个问题,是否可以更好地处理SQL查询中的COALESCE()列值,或者在golang代码中执行一些额外的编码?

3 个答案:

答案 0 :(得分:2)

作为一个选项,您可以实现与JSON Marshaler界面匹配的自定义数据类型。之后,您将能够使用常规标签封送您的结构。

检查示例:

type UserTitleType sql.NullString

func (s UserTitleType) MarshalJSON() ([]byte, error) {
    if s.Valid {
        return json.Marshal(s.String)
    }
    return jsonNull, nil
}

type User struct {
    Id    int64         `json:"id"`
    Title UserTitleType `json:"title"`
}

答案 1 :(得分:1)

您可以对sql包提供的类型使用别名,例如(NullInt64,NullString等...)。使用它有两个好处,一个可以扫描空值,可以使用golang结构,第二个可以用JSON编组该结构。

请查看示例代码:

// NullInt64 is an alias for sql.NullInt64 data type
type NullInt64 sql.NullInt64

// Scan implements the Scanner interface for NullInt64
func (ni *NullInt64) Scan(value interface{}) error {
    var i sql.NullInt64
    if err := i.Scan(value); err != nil {
        return err
    }
    // if nil the make Valid false
    if reflect.TypeOf(value) == nil {
        *ni = NullInt64{i.Int64, false}
    } else {
        *ni = NullInt64{i.Int64, true}
    }
    return nil
}

// MarshalJSON for NullInt64
func (ni *NullInt64) MarshalJSON() ([]byte, error) {
    if !ni.Valid {
        return []byte("null"), nil
    }
    return json.Marshal(ni.Int64)
}

请看一下这个article,在golang中处理空值以及如何在JSON中使用它会非常有用。

答案 2 :(得分:0)

// Scan implements the Scanner interface.
func (n *NullInt64) Scan(value interface{}) error {
    var ok bool
    if value == nil {
        n.Int64, n.Valid = 0, false
        return nil
    }

    n.Valid = true
    n.Int64, ok = value.(int64)
    if !ok {
        return errors.New("convert error")
    }
    return nil
}

// Value implements the driver Valuer interface.
func (n NullInt64) Value() (driver.Value, error) {
    if !n.Valid {
        return nil, nil
    }
    return n.Int64, nil
}