`?` заполнитель для условия SQL `IN` с постоянным`rawSql`
Я был бы счастлив использовать ?
заполнитель для заполнения идентификаторов для SQL IN
пункт. К сожалению это следующее не работает
let idList :: [ RequestId ]
idList = []
let sql :: String
sql = "SELECT ?? FROM request WHERE request.id IN ?"
rs <- runDB $ rawSql sql [ toPersistValue idList ]
Такой код приводит к ошибке базы данных, похожей на:
syntax error at or near "'[283,282,281]'"
Упаковка ?
заполнитель с скобками (например, IN (?)
) дает другой тип ошибки:
invalid input syntax for integer: "[283,282,281]"
Есть ли способ сделать это?
PS Похоже, это ужасное название, понятия не имею, как его улучшить
2 ответа
Я не думаю, что есть способ сделать это с persistent
,postrgresql-simple
(при условии, что мы говорим о Postgres здесь), который используется persistent
имеет специальную конструкцию In, которая корректно переводится в In (..) в SQL, но persistent
кажется, не использует это. Можно надеяться, что обходной путь - использовать конструктор PersistDbSpecific, который принимает ByteString
в качестве аргумента (чтобы мы могли вручную визуализировать и передавать что-то вроде (123,456,789)
) но, к сожалению, он преобразуется в SQL через Unknown, который затем обрабатывается через Escape, который не только экранирует строку, но и заключает ее в кавычки, что делает наш SQL недействительным. Если persistent
использовали Plain (что, на мой взгляд, имело бы гораздо больше смысла), этот подход будет работать, но, к сожалению, это не так.
Решение - не использовать
IN
, но более гибкий
ANY
функция:
let idList :: [ RequestId ]
idList = []
let sql :: String
sql = "SELECT ?? FROM request WHERE request.id = ANY(?)"
rs <- runDB $ rawSql sql [ PersistArray (map toPersistValue idList) ]
(
PersistArray
обеспечивает постоянное отображение списка с использованием литералов массива.
toPersistValue
одно только дает синтаксическую ошибку).
Вы можете узнать больше о синтаксисе на https://www.postgresql.org/docs/13/functions-comparisons.html (см.
ANY/SOME (array)
раздел).