Предлагает ли pgx какую-либо поддержку предложений «где в»? В другом потоке stackoverflow я обнаружил, что для создания запроса вручную следует использовать конкатенацию строк. IMO, это немного подвержено ошибкам, так как вы должны самостоятельно позаботиться об экранировании/внедрении sql и т.п.
Я тоже пытался разобраться сам:
const updatePurgedRecordingsStmt = "update recordings set status = 'DELETED', deleted = now() where status <> 'DELETED' and id in ($1);"
func (r *Repository) DeleteRecordings() error {
pool, err := r.connPool()
if err != nil {
return errors.Wrap(err, "cannot establish connection")
}
pgRecIds := &pgtype.Int4Array{}
if err := pgRecIds.Set([]int32{int32(1), int32(2)}); err != nil {
return errors.Wrap(err, "id conversion failed")
}
if _, err = pool.Exec(updatePurgedRecordingsStmt, pgRecIds); err != nil {
return errors.Wrap(err, "update stmt failed")
}
return nil
}
Когда я выполняю этот код, я получаю следующую ошибку:
ERROR: incorrect binary data format in bind parameter 1 (SQLSTATE 22P03)
Версии, которые я использую:
Постгрес:
db=> SELECT version();
version
-----------------------------------------------------------------------------------------------------------
PostgreSQL 9.6.11 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.2 20140120 (Red Hat 4.8.2-16), 64-bit
(1 row)
PGX:
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc=
github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
github.com/jackc/pgx v3.3.0+incompatible h1:Wa90/+qsITBAPkAZjiByeIGHFcj3Ztu+VzrrIpHjL90=
github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=

Как вы уже знаете, IN ожидает список скалярные выражения, а не массив, однако pgtype.Int4Array представляет множество, а не список скалярных выражений.
«ИМХО, это немного подвержено ошибкам, так как вы должны самостоятельно позаботиться об экранировании/внедрении sql и т.п.».
Не обязательно, вы можете зациклиться на своем массиве, построить строку ссылок на параметры, соединить ее с запросом, а затем выполнить ее, передав массив с помощью ....
var paramrefs string
ids := []interface{}{1,2,3,4}
for i, _ := range ids {
paramrefs += `$` + strconv.Itoa(i+1) + `,`
}
paramrefs = paramrefs[:len(paramrefs)-1] // remove last ","
query := `UPDATE ... WHERE id IN (` + paramrefs + `)`
pool.Exec(query, ids...)
В качестве альтернативы вы можете использовать ANY вместо IN.
ids := &pgtype.Int4Array{}
ids.Set([]int{1,2,3,4})
query := `UPDATE ... WHERE id = ANY ($1)`
pool.Exec(query, ids)
(здесь вам, возможно, придется привести ссылку param к соответствующему типу массива, я не уверен, попробуйте без приведения, если не в порядке, попробуйте с приведением)
Вы можете использовать Int8Array для []int64.
Можете ли вы привести пример того, как это будет работать со строками? например ... WHERE id = ANY ('string1', 'string2', ... );
@LoveenDyall По сути, это то же самое, что касается построения paramrefs: go.dev/play/p/VQ8UNWZRqSQ
Спасибо за ваш ответ! Мне пришлось привести идентификаторы к
[]int32, иначе Int4Array вернет ошибку преобразования.