dongyan4424 2017-02-25 21:42
浏览 206
已采纳

PostgreSQL插入多个表和行

I have 2 structs one Company the other Service. They have a has-many relationship company to service. I'm trying to write an SQL query that will insert a company and multiple services attached to that company in one query.

RAW SQL:

WITH company AS ( INSERT INTO companies(id, name) VALUES('1', 'acme') RETURNING id)
INSERT INTO services(id, company_id, name) VALUES
('1', (select company.id from company), 'cool service'),
('2', (select company.id from company), 'cooler service');

I'm trying to imitate this using go's sql package. This is my attempt thus far: I've added the structs at the top just for clarity

c := &Company{
    ID: uuid.NewV4().String(),
    Name: "test comp",
}

s := []*Service{
    &Service{
        ID: uuid.NewV4().String(),
        CompanyID: c.ID,
        Name: "test svc",
    },
}

c.Service = s

values := []interface{}{
    c.ID,
    c.Name,
}

q := `
    WITH company as (INSERT INTO companies(id, name) VALUES ($1, $2)) INSERT INTO services(id, company_id, name) VALUES
`

for _, row := range c.Services {
    q += "($1, $2, $3),"
    values = append(values, row.ID, row.CompanyID)
}

q = strings.TrimSuffix(q, ",")

stmt, err := s.DB.Prepare(q)
if err != nil {
    return err
}

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

I'm not sure how else to go about this but with this method I get this error:

ERROR #08P01 bind message supplies 5 parameters, but prepared statement "1" requires 3

Which makes sense I'm passing 5 parameters to exec when prepared statement "1" which I'm guessing is the second one only requires 3. But how can I perform my query without having to split it up into more than 1 query?

  • 写回答

1条回答 默认 最新

  • duanshan2988 2017-02-25 22:05
    关注

    Just as your error message says, your SQL statement only uses 3 bind variables:

       WITH company as (INSERT INTO companies(id, name) VALUES ($1, $2)) INSERT INTO services(id, company_id, name) VALUES
    

    and:

        q += "($1, $2, $3),"
    

    You're simply repeating $1, $2, and $3 for each of your rows. So your constructed query will look something like:

    WITH company as (INSERT INTO companies(id, name) VALUES ($1, $2)) INSERT INTO services(id, company_id, name) VALUES
    ($1, $2, $3),($1, $2, $3),($1, $2, $3),($1, $2, $3),
    

    Clearly that's not what you want. You need to increment your bind variable numbering with each iteration through the loop.

    My approach would probably be something like:

    var i int = 3
    for _, row := range c.Services {
        q += fmt.Sprintf("($%d, $%d, $%d),", i, i+1, i+2)
        values = append(values, row.ID, row.CompanyID)
        i += 3
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 安装svn网络有问题怎么办
  • ¥15 Python爬取指定微博话题下的内容,保存为txt
  • ¥15 vue2登录调用后端接口如何实现
  • ¥65 永磁型步进电机PID算法
  • ¥15 sqlite 附加(attach database)加密数据库时,返回26是什么原因呢?
  • ¥88 找成都本地经验丰富懂小程序开发的技术大咖
  • ¥15 如何处理复杂数据表格的除法运算
  • ¥15 如何用stc8h1k08的片子做485数据透传的功能?(关键词-串口)
  • ¥15 有兄弟姐妹会用word插图功能制作类似citespace的图片吗?
  • ¥15 latex怎么处理论文引理引用参考文献