2014-12-19 2 views
5

Я использую PostgreSQL 9.4 и удивительный тип поля JSONB. Я пытаюсь запросить поле в документе. Следующие работы в CLI PsqlPostgreSQL jsonb, `?` И JDBC

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: : No value specified for parameter 5. (SimpleParameterList.java:223)

(в моих реальных запросах есть больше параметров)

я могу обойти эту проблему путем литья моего параметра для ввода jsonb и с помощью оператора @> для проверки сдерживания.

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

Я не слишком увлечен работой. Я не знаю, есть ли штрафные санкции за исполнение, но это дополнительный набор текста и неочевидный.

Есть ли что-нибудь еще, что я могу сделать?

+0

Либо вы не вставляете код правильно, либо у вас есть синтаксическая ошибка: 'SQL (s" SELECT id FROM program WHERE document -> 'dept'? {Dept} .on ('dept -> "CS") ' → 'on' должны применяться к' SQL (...) ', не быть частью строки оператора, поскольку она, кажется, есть =' SQL ("..."). On (...) '. Примечание. эта строковая интерполяция бесполезна. – cchantep

+0

Я не вставлял весь вызов в SQL, потому что это не имеет отношения к моему запросу. Существует вызов 'apply' после' on' – Jason

+0

. Я бы лучше вставить код, который имеет действительный синтаксис, если вы хотите получить соответствующий ответ. – cchantep

ответ

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 -> Операторы для всех операторов, которые используют? во имя.

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 сделал что-либо (например, введя escape, как описано в ссылках выше) для решения этой проблемы. Быстрый взгляд на код и документацию свидетельствует о том, что они этого не сделали, но я не слишком много рыл.

Добавление: Как показано в the answer by bobmarksie, текущие версии драйвера PostgreSQL JDBC теперь поддерживает спасаясь знак вопроса, удвоив его (т.е. использовать ?? вместо ?).

+0

См. Мой ответ (http: // stac koverflow.com/a/35359516/1692179). В документации PosgreSQL доступно и описано (начиная с февраля 2016 г.). – bobmarksie

+0

@bobmarksie Спасибо, я добавил примечание об этом. –

2

У меня была такая же проблема несколько дней назад, и после некоторого расследования я нашел это.

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

In JDBC, the question mark (?) is the placeholder for the positional parameters of a PreparedStatement. There are, however, a number of PostgreSQL operators that contain a question mark. To keep such question marks in a SQL statement from being interpreted as positional parameters, use two question marks (??) as escape sequence. You can also use this escape sequence in a Statement, but that is not required. Specifically only in a Statement a single (?) can be used as an operator.

Использование 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'] 

Надеемся, что это работает с вашим сценарием!

Смежные вопросы