`?` SQL `IN` 条件的占位符与持久的 `rawSql`

`?` placeholder for SQL `IN` condition with persistent's `rawSql`

我很乐意使用 ? 占位符来填充 SQL IN 子句的 ID。不幸的是以下不起作用

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]"

有没有办法做到这一点?

P.S。看起来这是一个糟糕的标题,不知道如何改进它

我认为 persistent 没有办法做到这一点。 postrgresql-simple(假设我们在这里谈论的是 Postgres)persistent 使用的 In construct which is correctly translated into In (..) 在 SQL 中确实有特殊的 In construct which is correctly translated into In (..),但 persistent 似乎没有用它。 人们可能希望一种解决方法是使用 PersistDbSpecific constructor which takes ByteString as an argument (so we could manually render and pass something like (123,456,789)) but unfortunately it is converted into SQL via Unknown which is then rendered via Escape which not only escapes the string but also encloses it into quotes which makes our SQL invalid. If persistent were using 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) 部分)。