PostgreSQL插入多个表和行

PostgreSQL插入多个表和行,sql,postgresql,go,Sql,Postgresql,Go,我有两个结构一个公司另一个服务。他们有许多需要服务的关系公司。我正在尝试编写一个SQL查询,它将在一个查询中插入一个公司和多个附加到该公司的服务 原始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 compan

我有两个结构一个公司另一个服务。他们有许多需要服务的关系公司。我正在尝试编写一个SQL查询,它将在一个查询中插入一个公司和多个附加到该公司的服务

原始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');
我正试图用go的sql包来模拟这一点。这是我迄今为止的尝试:为了清晰起见,我在顶部添加了结构

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
}
我不知道还有什么其他方法可以做到这一点,但使用此方法我会遇到以下错误:

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

当准备好的语句“1”时,我将5个参数传递给exec,我猜第二个语句只需要3个参数,这是有道理的。但是,如何执行查询而不必将其拆分为多个查询?

正如错误消息所述,SQL语句仅使用3个绑定变量:

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

您只需为每行重复
$1
$2
$3
。因此,构建的查询将类似于:

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),
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
}
显然这不是你想要的。您需要在循环的每次迭代中增加绑定变量编号

我的方法可能是:

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),
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
}

我不会在for循环的每次迭代中递增,而是在使用的每个绑定变量中递增。@Rodrigo:我的方法是在循环中每次递增一个变量3。如果您喜欢三个独立的迭代,那么也可以这样做。你挑吧,既然你回答了我的问题,我就把你的答案标为正确。虽然整个方法感觉很臭。有没有更好的办法?就像不只是尝试修复我的黑客方法一样?一些后端驱动程序支持使用
,甚至是命名参数。但不幸的是,
pq
驱动程序似乎不支持这一点。另一种选择可能是使用该库,它在
sql
包的顶部添加了命名参数支持,因此它可以用于任何后端。我不确定这对你来说是否更容易。