首页 > 解决方案 > 使用 jackc/pgx 将空字符串或 null 作为 null 插入 postgres

问题描述

我使用的外部 json API 处理缺失值的方式不一致。有时 json 值显示为空字符串,有时显示为 null。例如...

Case1: datedecandcurr都是空字符串。

{
    "symbol": "XYZ",
    "dateex": "2020-09-01",
    "datedec": "",
    "amount": "1.25",
    "curr": "",
    "freq": "annual"
}

案例2:datedec为空。curr被填充。

{
    "symbol": "XYZ",
    "dateex": "2020-09-01",
    "datedec": null,
    "amount": "1.25",
    "curr": "USD",
    "freq": "annual"
}

这是我用来表示股息的结构:

type Dividend struct {
    symbol   string `json:"symbol"`
    dateex   string `json:"dateex"`
    datedec  string `json:"datedec"`
    amount   string `json:"amount"`
    curr     string `json:"curr"`
    freq     string `json:"freq"`
}

我遇到的问题是如何将空字符串或 null 作为NULL. 我知道我可以使用omitemptyjson 标签,但是我将如何编写一个函数来处理我不知道会丢失的值?例如,这是我当前使用 jackc/pgx 包在 postgresql 中插入股息的函数:

func InsertDividend(d Dividend) error {
    sql := `INSERT INTO dividends 
    (symbol, dateex, datedec, amount, curr, freq)
    VALUES ($1, $2, $3, $4, $5, $6)`
    conn, err := pgx.Connect(ctx, "DATABASE_URL")
    // handle error 
    defer conn.Close(ctx)
    tx, err := conn.Begin()
    // handle error
    defer tx.Rollback(ctx)
    _, err = tx.Exec(ctx, sql, d.symbol, d.dateex, d.datedec, d.amount, d.curr, d.freq)
    // handle error
    }
    err = tx.Commit(ctx)
    // handle error
    return nil
}

如果缺少值(例如 datedec 或 curr),则此函数将出错。从这篇文章Golang Insert NULL into sql instead of empty string我看到了如何解决 Case1。但是有没有更通用的方法来处理这两种情况(空字符串或空字符串)?

我一直在查看 database/sql & jackc/pgx 文档,但我还没有找到任何东西。我认为 sql.NullString 有潜力,但我不确定我应该怎么做。

任何建议将不胜感激。谢谢!

标签: sqlpostgresqlgopgx

解决方案


NULL写入数据库时​​,您可以通过多种方式表示。sql.NullString是使用指针 ( nil= null) 的选项;选择实际上归结为您发现更容易理解的内容。罗斯考克斯评论说

没有有效的区别。我们认为人们可能想要使用 NullString,因为它很常见,并且可能比 *string 更清楚地表达了意图。但两者都行。

我怀疑在您的情况下使用指针将是最简单的方法。例如,以下内容可能会满足您的需求:

type Dividend struct {
    Symbol  string  `json:"symbol"`
    Dateex  string  `json:"dateex"`
    Datedec *string `json:"datedec"`
    Amount  string  `json:"amount"`
    Curr    *string `json:"curr"`
    Freq    string  `json:"freq"`
}

func unmarshal(in[]byte, div *Dividend) {
    err := json.Unmarshal(in, div)
    if err != nil {
        panic(err)
    }
    // The below is not necessary unless if you want to ensure that blanks
    // and missing values are both written to the database as NULL...
    if div.Datedec != nil && len(*div.Datedec) == 0 {
        div.Datedec = nil
    }
    if div.Curr != nil && len(*div.Curr) == 0 {
        div.Curr = nil
    }
}

在操场上试试。

Dividend在写入数据库时​​,您可以像现在一样使用结构;nilSQL 驱动程序会将NULL.


推荐阅读