@@ -185,6 +185,8 @@ func (q *Queries) GetInfoForAuthor(ctx context.Context, id int) (GetInfoForAutho
185185
186186## Passing a slice as a parameter to a query
187187
188+ ### PostgreSQL
189+
188190In PostgreSQL,
189191[ ANY] ( https://www.postgresql.org/docs/current/functions-comparisons.html#id-1.5.8.28.16 )
190192allows you to check if a value exists in an array expression. Queries using ANY
@@ -262,3 +264,111 @@ func (q *Queries) ListAuthorsByIDs(ctx context.Context, ids []int) ([]Author, er
262264 return items, nil
263265}
264266```
267+
268+ ### MySQL
269+
270+ MySQL differs from PostgreSQL in that placeholders must be generated based on
271+ the number of elements in the slice you pass in. Though trivial it is still
272+ something of a nuisance. The passed in slice must not be nil or empty or an
273+ error will be returned (ie not a panic). The placeholder insertion location is
274+ marked by the meta-function ` sqlc.slice() ` (which is similar to ` sqlc.arg() `
275+ that you see documented under [ Naming parameters] ( named_parameters.md ) ).
276+
277+ To rephrase, the ` sqlc.slice('param') ` behaves identically to ` sqlc.arg() ` it
278+ terms of how it maps the explicit argument to the function signature, eg:
279+
280+ * ` sqlc.slice('ids') ` maps to ` ids []GoType ` in the function signature
281+ * ` sqlc.slice(cust_ids) ` maps to ` custIds []GoType ` in the function signature
282+ (like ` sqlc.arg() ` , the parameter does not have to be quoted)
283+
284+ This feature is not compatible with ` emit_prepared_queries ` statement found in the
285+ [ Configuration file] ( ../reference/config.md ) .
286+
287+ ``` sql
288+ CREATE TABLE authors (
289+ id SERIAL PRIMARY KEY ,
290+ bio text NOT NULL ,
291+ birth_year int NOT NULL
292+ );
293+
294+ -- name: ListAuthorsByIDs :many
295+ SELECT * FROM authors
296+ WHERE id IN (sqlc .slice (' ids' ));
297+ ```
298+
299+ The above SQL will generate the following code:
300+
301+ ``` go
302+ package db
303+
304+ import (
305+ " context"
306+ " database/sql"
307+ " fmt"
308+ " strings"
309+ )
310+
311+ type Author struct {
312+ ID int
313+ Bio string
314+ BirthYear int
315+ }
316+
317+ type DBTX interface {
318+ ExecContext (context.Context , string , ...interface {}) (sql.Result , error )
319+ PrepareContext (context.Context , string ) (*sql.Stmt , error )
320+ QueryContext (context.Context , string , ...interface {}) (*sql.Rows , error )
321+ QueryRowContext (context.Context , string , ...interface {}) *sql.Row
322+ }
323+
324+ func New (db DBTX ) *Queries {
325+ return &Queries{db: db}
326+ }
327+
328+ type Queries struct {
329+ db DBTX
330+ }
331+
332+ func (q *Queries ) WithTx (tx *sql .Tx ) *Queries {
333+ return &Queries{
334+ db: tx,
335+ }
336+ }
337+
338+ const listAuthorsByIDs = ` -- name: ListAuthorsByIDs :many
339+ SELECT id, bio, birth_year FROM authors
340+ WHERE id IN (/*SLICE:ids*/?)
341+ `
342+
343+ func (q *Queries ) ListAuthorsByIDs (ctx context .Context , ids []int64 ) ([]Author , error ) {
344+ sql := listAuthorsByIDs
345+ var queryParams []interface {}
346+ if len (ids) == 0 {
347+ return nil , fmt.Errorf (" slice ids must have at least one element" )
348+ }
349+ for _ , v := range ids {
350+ queryParams = append (queryParams, v)
351+ }
352+ sql = strings.Replace (sql, " /*SLICE:ids*/?" , strings.Repeat (" ,?" , len (ids))[1 :], 1 )
353+ rows , err := q.db .QueryContext (ctx, sql, queryParams...)
354+ if err != nil {
355+ return nil , err
356+ }
357+ defer rows.Close ()
358+ var items []Author
359+ for rows.Next () {
360+ var i Author
361+ if err := rows.Scan (&i.ID , &i.Bio , &i.BirthYear ); err != nil {
362+ return nil , err
363+ }
364+ items = append (items, i)
365+ }
366+ if err := rows.Close (); err != nil {
367+ return nil , err
368+ }
369+ if err := rows.Err (); err != nil {
370+ return nil , err
371+ }
372+ return items, nil
373+ }
374+ ```
0 commit comments