Хобрук: Ваш путь к мастерству в программировании

PostgreSQL jsonb, `?` и JDBC

Я использую PostgreSQL 9.4 и потрясающий тип поля JSONB. Я пытаюсь запросить поле в документе. Следующее работает в интерфейсе командной строки psql

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

Когда я пытаюсь выполнить тот же запрос через свое приложение Scala, я получаю сообщение об ошибке ниже. Я использую Play framework и 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")
....

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

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

19.12.2014

  • Либо вы неправильно вставляете код, либо у вас есть синтаксическая ошибка: SQL(s"SELECT id FROM program WHERE document -> 'dept' ? {dept} .on('dept -> "CS")on должно применяться к SQL(...), а не быть частью строки оператора, как кажется, там = SQL("...").on(...). Обратите внимание, что интерполяция строк здесь бесполезна. 20.12.2014
  • Я не вставлял весь вызов SQL, потому что он не имеет отношения к моему вопросу. Есть вызов apply после on 20.12.2014
  • Мне было бы лучше вставить код с допустимым синтаксисом, если вы хотите получить соответствующий ответ. 20.12.2014
  • Кажется, в последнем драйвере JDBC есть исправление, которое позволяет избежать вопросительного знака, удвоив его: ??. См. postgresql.org/message-id/ 14.08.2015

Ответы:


1

В качестве обходного пути, чтобы избежать ? вы можете создать новый оператор, делая то же самое.

Это код исходного оператора:

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

20.12.2014

2

В JDBC (и стандартном SQL) вопросительный знак зарезервирован в качестве заполнителя параметра. Другие виды использования не допускаются.

См. Предотвращает ли спецификация JDBC '?' от использования в качестве оператора (вне кавычек)? и обсуждение jdbc-spec-discuss.

Текущий драйвер PostgreSQL JDBC будет преобразовывать все вхождения (вне текста или комментариев) вопросительного знака в специальный заполнитель параметра PostgreSQL. Я не уверен, сделал ли проект PostgreSQL JDBC что-нибудь (например, внедрил экранирование, как обсуждалось в ссылках выше), чтобы решить эту проблему. Беглый взгляд на код и документацию показывает, что это не так, но я не копал слишком глубоко.

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

20.12.2014
  • См. мой ответ (stackoverflow.com/a/35359516/1692179) - экранирование доступно и описано (по состоянию на февраль 2016 г.) в документации PosgreSQL. 13.02.2016

  • 3

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

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

    В JDBC вопросительный знак (?) является заполнителем для позиционных параметров PreparedStatement. Однако есть ряд операторов PostgreSQL, которые содержат вопросительный знак. Чтобы такие вопросительные знаки в операторе SQL не интерпретировались как позиционные параметры, используйте два вопросительных знака (??) в качестве управляющей последовательности. Вы также можете использовать эту управляющую последовательность в операторе, но это не обязательно. В частности, только в операторе один (?) может использоваться в качестве оператора.

    Использование двух вопросительных знаков, похоже, хорошо сработало для меня - я использовал следующий драйвер (проиллюстрированный с использованием зависимости от 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']
    

    ... to ...

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

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

    12.02.2016

    4

    Как сказал Боб, просто используйте ?? вместо ?

    SQL(s"SELECT id FROM program WHERE document -> 'dept' ?? {dept}")
    .on('dept -> "CS")
    
    30.05.2019
    Новые материалы

    Получение стоковых обновлений с помощью Python
    Для начинающего финансового аналитика Введение Описание: Этот проект Python создает скрипт для получения текущих обновлений акций с финансового веб-сайта Yahoo. Для этого проекта мы..

    Это все, что вам нужно знать о Kotlin в 2022 году
    Добро пожаловать! Kotlin — это язык программирования, популярность которого, кажется, растет, его действительно можно использовать для создания чего угодно, и если вы хотите узнать о Kotlin,..

    Текстовый графический интерфейс с Lanterna на Java
    Мой опыт работы с компьютерами (и текстовыми графическими пользовательскими интерфейсами) начался еще в восьмидесятых, когда я был ребенком, на дне рождения друга. Это был «новенький» Amstrad..

    Перезарядите свой мозг: умопомрачительный потенциал мозговых компьютерных интерфейсов
    Способность читать свои мысли и управлять объектами разумом долгое время были предметом человеческого любопытства, ограниченного областью научной фантастики… то есть до сих пор? С технологией,..

    Основы C# — Нулевой оператор объединения (??)
    Оператор ?? называется null-coalescing operator . Этот оператор используется для предоставления значения по умолчанию, если значение операнда в левой части оператора равно null ...

    Сравнение номеров версий в C++ с использованием синтаксического анализа строк
    Номера версий обычно используются для обозначения развития или обновлений программного обеспечения или любого другого продукта. При работе с номерами версий в C++ может быть полезно сравнить две..

    В мир искусственного интеллекта…
    ИИ — это новое топливо в современном мире. Куда бы вы ни обратились, с кем бы вы ни разговаривали — они, как правило, упоминают об ИИ хотя бы раз в ходе разговора. ИИ гудит повсюду. У каждого..