GoでSQL発行時に渡す変数を可変にする

Web画面に複数のチェックボックスが表示されていて、ユーザが自由に任意の数を選択してsubmitされたりした場合、IN句が可変になったりする場合がある。

どうやって可変長の変数を渡すのだろう?というのが気になった。

で、試行錯誤の末、以下のようにしたら動いた。

まずこんな感じのdocker-compose.yamlを用意してdocker-composeでPostgreSQLを起動しておいて、

services:
  db:
    image: postgres:14
    container_name: postgresql
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_INITDB_ARGS: "--no-locale"
    volumes:
      - ./pgdata:/var/lib/postgresql/data
      - ./pginit:/docker-entrypoint-initdb.d

以下のようなコードにしたらうまくいった。ポイントは、any型の配列に渡したい変数を格納するのと、関数呼び出し時にその変数を渡しつつ、変数の後に...と書く、というところ。

package main

import (
    "database/sql"
    "log"

    _ "github.com/lib/pq"
)

func main() {
    conn, err := sql.Open("postgres", "host=127.0.0.1 port=5432 dbname=postgres user=postgres password=postgres sslmode=disable")
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    _, err = conn.Exec(`DROP TABLE IF EXISTS a;`)
    if err != nil {
        log.Println(err)
        return
    }
    _, err = conn.Exec(`CREATE TABLE a(id integer, value text)`)
    if err != nil {
        log.Fatal(err)
    }
    _, err = conn.Exec(`INSERT INTO a VALUES(1, 'あ')`)
    if err != nil {
        log.Fatal(err)
    }
    _, err = conn.Exec(`INSERT INTO a VALUES(2, 'い')`)
    if err != nil {
        log.Fatal(err)
    }
    _, err = conn.Exec(`INSERT INTO a VALUES(3, 'う')`)
    if err != nil {
        log.Fatal(err)
    }
    // any型の配列にする
    bind := []any{"あ", "い"}
    // 最後に...をつける
    rows, err := conn.Query(`SELECT id, value FROM a WHERE value IN ($1, $2)`, bind...)
    if err != nil {
        log.Fatal(err)
    }
    for rows.Next() {
        var id int
        var value string
        err = rows.Scan(&id, &value)
        if err != nil {
            log.Fatal(err)
        }
        log.Println(id, value)
    }
}