【问题标题】:Bulk insert from csv in postgres using golang without using for loop使用golang在postgres中从csv批量插入而不使用for循环
【发布时间】:2021-06-21 01:30:01
【问题描述】:

我是 Golang 新手,

  • 我有一个 csv 文件,其中的数据看起来像这样
field1,field2
1.1,2
1.2,3
1.3,2
  • 我想使用 golang 将所有 csv 数据插入到 db 表中,而不使用 for 循环。我正在使用 postgres 数据库

也不想使用 sql raw 查询

我正在使用 gorm ORM

【问题讨论】:

  • 您能展示一下到目前为止您尝试过的内容吗?您具体要避免什么循环?读取 csv 记录的循环,插入单个记录的循环?你能展示一下你用什么数据结构来表示 Go 中的 csv 数据吗?
  • 是的,我不想遍历 csv 记录
  • 如果不是SQL,那你想用什么?你在使用一些 ORM 吗?
  • 标准 golang 执行原始 SQL 将记录插入数据库。
  • 如前所述,使用batch insert,然后。

标签: database postgresql go go-gorm


【解决方案1】:

您可以为此使用pgx 库:

    filename := "foo.csv"
    dbconn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
    if err != nil {
        panic(err)
    }
    defer dbconn.Release()
    f, err := os.Open(filename)
    if err != nil {
        panic(err)
    }
    defer func() { _ = f.Close() }()
    res, err := dbconn.Conn().PgConn().CopyFrom(context.Background(), f, "COPY csv_test FROM STDIN (FORMAT csv)")
    if err != nil {
        panic(err)
    }
    fmt.Print(res.RowsAffected())

【讨论】:

  • 不确定是否是由于我使用 pgx/v4 造成的,但这无法编译。这部分没有:dbconn.Conn().PgConn().CopyFrom应该使用哪个pgx版本?
  • 尝试使用这种方法stackoverflow.com/a/68749440/1109280
  • 谢谢!那是我的帖子,从你那里弄清楚了。我必须专门使用 pgx 的 v1 而不是最新的 v4。谢谢@Pavlo Golub
  • 哦,我明白了。我肯定使用v4。但也许我的代码示例中打印错误,因为我是从工作项目中提取它。你可以在这里找到它:github.com/cybertec-postgresql/pg_timetable/blob/master/…
【解决方案2】:

您可以将 CSV 解析为一个类型化结构的片段using an external library,然后使用 GORM 的batch insert 一次性将它们全部插入。

这是一个例子:

import (
    "os"

    "github.com/gocarina/gocsv"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

// Entry defines both the CSV layout and database schema
type Entry struct {
    gorm.Model

    Field1 float64 `csv:"field1"`
    Field2 float64 `csv:"field2"`
}

func main() {
    // Open the CSV file for reading
    file, err := os.Open("data.csv")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    // Parse CSV into a slice of typed data `[]Entry` (just like json.Unmarshal() does)
    // The builtin package `encoding/csv` does not support unmarshaling into a struct
    // so you need to use an external library to avoid writing for-loops.
    var entries []Entry
    err = gocsv.Unmarshal(file, &entries)
    if err != nil {
        panic(err)
    }

    // Open a postgres database connection using GORM
    db, err := gorm.Open(postgres.Open("host=localhost user=postgres password=dev dbname=foo port=5432 sslmode=disable TimeZone=Europe/Paris"))
    if err != nil {
        panic(err)
    }

    // Create `entries` table if not exists
    err = db.AutoMigrate(&Entry{})
    if err != nil {
        panic(err)
    }

    // Save all the records at once in the database
    result := db.Create(entries)
    if result.Error != nil {
        panic(result.Error)
    }
}

【讨论】:

  • 我试图避免定义模式。我希望能够导出数据并重新导入,而无需处理其间的架构。
猜你喜欢
  • 1970-01-01
  • 2018-10-04
  • 2014-07-23
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多