【问题标题】:PostgreSQL jsonb, `?` and JDBCPostgreSQL jsonb、`?` 和 JDBC
【发布时间】:2015-02-18 20:17:56
【问题描述】:

我正在使用 PostgreSQL 9.4 和很棒的 JSONB 字段类型。我正在尝试查询文档中的字段。以下在 psql CLI 中工作

SELECT id FROM program WHERE document -> 'dept' ? 'CS'

当我尝试通过我的 Scala 应用程序运行相同的查询时,我收到以下错误。我正在使用 Play 框架和 Anorm,所以查询看起来像这样

SQL(s"SELECT id FROM program WHERE document -> 'dept' ? {dept}")
.on('dept -> "CS")
....

SQLException: : 没有为参数 5 指定值。 (SimpleParameterList.java:223)

(在我的实际查询中有更多参数)

我可以通过将参数转换为 jsonb 类型并使用 @> 运算符来检查包含情况来解决此问题。

SQL(s"SELECT id FROM program WHERE document -> 'dept' @> {dept}::jsonb")
.on('dept -> "CS")
....

我不太热衷于解决问题。我不知道演员表是否有性能损失,但这是额外的打字,而且不明显。

还有什么我可以做的吗?

【问题讨论】:

  • 要么你没有正确粘贴代码,要么你有语法错误:SQL(s"SELECT id FROM program WHERE document -> 'dept' ? {dept} .on('dept -> "CS") → on 必须应用于SQL(...),而不是看起来像是语句字符串的一部分那里=SQL("...").on(...)。注意那里的字符串插值是没用的。
  • 我没有将整个调用粘贴到 SQL,因为它与我的问题无关。在on 之后有一个对apply 的调用
  • 如果您想要适当的答案,我会更好地粘贴具有有效语法的代码。
  • 最新的 JDBC 驱动程序中似乎有一个修复程序,允许通过加倍来转义问号:??。见postgresql.org/message-id/…

标签: postgresql jdbc anorm jsonb


【解决方案1】:

在 JDBC(和标准 SQL)中,问号保留为参数占位符。不允许其他用途。

参见Does the JDBC spec prevent '?' from being used as an operator (outside of quotes)? 和discussion on jdbc-spec-discuss。

当前的 PostgreSQL JDBC 驱动程序会将所有出现的问号(文本或 cmets 之外)转换为 PostgreSQL 特定的参数占位符。我不确定 PostgreSQL JDBC 项目是否已经做了任何事情(比如在上面的链接中讨论引入转义)来解决这个问题。快速浏览一下代码和文档表明他们没有,但我没有深入挖掘。

附录:如the answer by bobmarksie 所示,当前版本的 PostgreSQL JDBC 驱动程序现在支持通过加倍转义问号(即:使用?? 而不是?)。

【讨论】:

【解决方案2】:

作为避免 ?运算符,你可以创建一个 new operator 做同样的事情。

这是原始操作符的代码:

CREATE OPERATOR ?(
  PROCEDURE = jsonb_exists,
  LEFTARG = jsonb,
  RIGHTARG = text,
  RESTRICT = contsel,
  JOIN = contjoinsel);

SELECT '{"a":1, "b":2}'::jsonb ? 'b'; -- true

使用不同的名称,没有任何冲突,例如 #-# 并创建一个新名称:

CREATE OPERATOR #-#(
  PROCEDURE = jsonb_exists,
  LEFTARG = jsonb,
  RIGHTARG = text,
  RESTRICT = contsel,
  JOIN = contjoinsel);

SELECT '{"a":1, "b":2}'::jsonb #-# 'b'; -- true

在您的代码中使用这个新的运算符,它应该可以工作。

检查 pgAdmin -> pg_catalog -> Operators 以了解所有使用 ?以名字命名。

【讨论】:

    【解决方案3】:

    几天前我遇到了同样的问题,经过一番调查后我发现了这个问题。

    https://jdbc.postgresql.org/documentation/head/statement.html

    在 JDBC 中,问号 (?) 是 PreparedStatement 位置参数的占位符。但是,有许多 PostgreSQL 运算符包含问号。要防止 SQL 语句中的此类问号被解释为位置参数,请使用两个问号 (??) 作为转义序列。您也可以在语句中使用此转义序列,但这不是必需的。具体来说,只有在语句中,单个 (?) 可以用作运算符。

    使用 2 个问号对我来说似乎效果很好 - 我使用的是以下驱动程序(使用 maven 依赖项说明)...

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>9.4-1201-jdbc41</version>
        </dependency>
    

    ... 和 MyBatis 用于创建 SQL 查询,它似乎运行良好。似乎比创建 PostgreSQL 运算符更容易/更干净。

    SQL 来自例如

    select * from user_docs where userTags ?| array['sport','property']
    

    ...到...

    select * from user_docs where userTags ??| array['sport','property']
    

    希望这适用于您的场景!

    【讨论】:

      【解决方案4】:

      正如鲍勃所说,只需使用 ?? 而不是 ?

      SQL(s"SELECT id FROM program WHERE document -> 'dept' ?? {dept}")
      .on('dept -> "CS")
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-12-12
        • 1970-01-01
        • 2021-10-19
        • 1970-01-01
        • 1970-01-01
        • 2012-12-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多