PostgreSQL jsonb,`?`和JDBC

时间:2014-12-19 20:56:19

标签: postgresql jdbc anorm jsonb

我正在使用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")
....

我不太热衷于工作。我不知道是否会对演员表现出性能损失,但这是额外的打字,并且不明显。

我还能做些什么吗?

4 个答案:

答案 0 :(得分:7)

作为避免的解决方法?运算符,您可以创建一个完全相同的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 - >所有运营商使用的运营商?在名称中。

答案 1 :(得分:4)

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

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

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

附录:如the answer by bobmarksie所示,PostgreSQL JDBC驱动程序的当前版本现在支持通过加倍来回避问号(即:使用??代替{{ 1}})。

答案 2 :(得分:2)

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

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

  

在JDBC中,问号(var textarea = document.getElementsByName("your-message")[0]; textarea.value = booking; )是PreparedStatement的位置参数的占位符。但是,有许多PostgreSQL运算符包含问号。要使SQL语句中的此类问号不被解释为位置参数,请使用两个问号(?)作为转义序列。您也可以在Statement中使用此转义序列,但这不是必需的。特别是在语句中,单个(??)可以用作运算符。

使用2个问号似乎对我有用 - 我使用以下驱动程序(使用maven依赖关系说明)...

?

...和MyBatis用于创建SQL查询,它似乎运行良好。看起来比创建PostgreSQL运算符更容易/更清洁。

SQL来自例如

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

...到......

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

希望这适用于您的场景!

答案 3 :(得分:0)

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

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