为了账号安全,请及时绑定邮箱和手机立即绑定

对行的唯一约束冲突会导致整个 pq。CopyIn postgresql 导入失败

对行的唯一约束冲突会导致整个 pq。CopyIn postgresql 导入失败

Go
牧羊人nacy 2022-09-19 14:46:59
我正在尝试使用 pq。CopyIn 执行批量导入,如下所述:https://godoc.org/github.com/lib/pq导入比我尝试过的其他方法快得多,但我发现仅在一条记录中发生唯一约束冲突将导致整个导入失败。有没有办法设置冲突 不使用pq不做任何事情.文案。这是我的表格结构的副本CREATE TABLE test (    id serial PRIMARY KEY,    unique_token VARCHAR ( 10 ) UNIQUE NOT NULL,    frequency INT DEFAULT 0);我尝试在下面使用@mkopriva答案,但我得到错误:pq:列“id”中的空值违反了非空约束下面的代码示例tx, _ := db.Begin()_, err = tx.Exec(`CREATE TEMP TABLE token_temp ON COMMIT DROP AS    SELECT id, unique_token FROM test WITH NO DATA`)if err != nil {    return err}stmt, err := tx.Prepare(pq.CopyIn("token_temp", "unique_token"))if err != nil {    fmt.Println("error here")    return err}for _, token := range tokenList {    _, err = stmt.Exec(token)    if err != nil {        return err    }}_, err = stmt.Exec()if err != nil {    log.Fatal(err)}err = stmt.Close()if err != nil {    log.Fatal(err)}_, err = tx.Exec(`INSERT INTO test SELECT id, unique_token FROM   token_temp   ON CONFLICT(unique_token) DO UPDATE SET frequency=    test.frequency + 1 `)if err != nil {    fmt.Println("Error")    return err}err = tx.Commit()if err != nil {    log.Fatal(err)}
查看完整描述

1 回答

?
MM们

TA贡献1886条经验 获得超2个赞

pq.CopyIn内部使用 COPY FROM,它不支持该子句。ON CONFLICT


但是,您可以做的是创建一个没有约束的临时表,将数据复制到该临时表中,然后使用您的子句在目标表中执行 操作,使用临时表作为要插入的数据源。INSERTON CONFLICT


一个例子应该更清楚地说明这一点,假设你有一个看起来像这样的表:users


CREATE TABLE users (

    id serial PRIMARY KEY

    , name text

    , email text UNIQUE

);

假设你有一部分用户像这样:


var users = []User{

    {Name: "John Doe", Email: "jdoe@example.com"},

    {Name: "Joe Blow", Email: "jblow@example.com"},

    {Name: "Jane Doe", Email: "jdoe@example.com"}, // duplicate email!

    {Name: "Foo Bar", Email: "fbar@example.com"},

}

这样,您可以执行以下操作:


_, err = txn.Exec(`

CREATE TEMP TABLE users_temp

ON COMMIT DROP

AS SELECT * FROM users

WITH NO DATA`)

if err != nil {

    panic(err)

}


stmt, err := txn.Prepare(pq.CopyIn("users_temp", "name", "email"))

if err != nil {

    panic(err)

}


for _, u := range users {

    if _, err := stmt.Exec(u.Name, u.Email); err != nil {

        panic(err)

    }

}

if _, err := stmt.Exec(); err != nil {

    panic(err)

}

if err := stmt.Close(); err != nil {

    panic(err)

}


_, err = txn.Exec(`

INSERT INTO users (name, email)

SELECT name, email FROM users_temp

ON CONFLICT DO NOTHING`)

if err != nil {

    panic(err)

}


if err := txn.Commit(); err != nil {

    panic(err)

}

运行上述操作后,您可以这样做,您将获得以下内容:SELECT * FROM users;


 id |   name   |       email

----+----------+-------------------

  1 | John Doe | jdoe@example.com

  2 | Joe Blow | jblow@example.com

  4 | Foo Bar  | fbar@example.com

(3 rows)

对于特定的示例和要求,您可以在查询中执行如下操作:INSERT ... SELECT ...


_, err = txn.Exec(`

INSERT INTO test (unique_token, frequency)

SELECT unique_token, COUNT(*) FROM token_temp

GROUP BY unique_token`)

if err != nil {

    panic(err)

}


查看完整回答
反对 回复 2022-09-19
  • 1 回答
  • 0 关注
  • 120 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号