带有持久变量`rawSql`

时间:2019-01-16 13:33:11

标签: sql haskell yesod persistent 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。看来这标题太可怕了,不知道该如何改进

2 个答案:

答案 0 :(得分:1)

我认为persistent没有办法。 postrgresql-simple使用的persistent(假设我们在这里谈论的是Postgres)确实具有特殊的In构造,该构造可以在SQL中正确转换为In (..),但是{{1 }}似乎没有使用它。 可能希望一种解决方法是使用PersistDbSpecific构造函数,该构造函数以persistent作为参数(以便我们可以手动呈现并传递类似ByteString的东西),但不幸的是,它通过{然后通过Unknown呈现的{3}}不仅使字符串转义,而且使Escape无效,这使我们的SQL无效。如果(123,456,789)使用的是encloses it into quotes(我认为这样会更有意义),则此方法有效,但不幸的是,并非如此。

答案 1 :(得分:1)

解决办法是不使用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) 部分)。