У меня есть таблица, persons
которая содержит два столбца, id
и столбец на основе JSONB data
(эта таблица была только что сделана в демонстрационных целях, чтобы поиграться с поддержкой JSON в PostgreSQL).
Теперь предполагается, что он содержит две записи:
1, { name: 'John', age: 30 }
2, { name: 'Jane', age: 20 }
Предположим, я хочу получить имя каждого человека старше 25 лет. Я попробовал:
select data->'name' as name from persons where data->'age' > 25
К сожалению, это приводит к ошибке. Я могу решить эту проблему, используя ->>
вместо этого ->
, но тогда сравнения не будут работать так, как ожидалось, поскольку сравниваются не числа, а их представления в виде строк:
select data->'name' as name from persons where data->>'age' > '25'
Затем я понял, что на самом деле могу решить проблему, используя ->
и приведение к int
:
select data->'name' as name from persons where cast(data->'age' as int) > 25
Это работает, но не очень приятно, что мне нужно знать фактический тип (тип age
документа JSON в number
любом случае таков, так почему же PostgreSQL не может выяснить это сам по себе?).
Затем я понял, что, если я вручную преобразую text
в ::
синтаксис, все тоже будет работать, как и ожидалось - хотя мы сейчас снова сравниваем строки.
select data->'name' as name from persons where data->'age'::text > '25'
Если я тогда попробую это с именем вместо возраста, это не сработает:
select data->'name' as name from persons where data->'name'::text > 'Jenny'
Это приводит к ошибке:
неверный синтаксис ввода для типа json
Совершенно очевидно, что я ничего не понимаю здесь. К сожалению, довольно сложно найти какие-либо реальные примеры использования JSON с PostgreSQL.
Есть намеки?
источник
data->'name'::text
, вы'name'
приводите строку к тексту, а не результат. Вы не получите ошибку при сравнении с,'25'
потому что25
это допустимый литерал JSON; ноJenny
это не так (хотя"Jenny"
было бы).'Jenny'
с'"Jenny"'
.Ответы:
Это не работает, потому что он пытается привести
jsonb
значение кinteger
.Это на самом деле будет работать:
Или короче:
И это:
Похоже, путаница с двумя операторами
->
и->>
и приоритет оператора . Приведение::
связывается сильнее, чем операторы json (b).Определить тип динамически
Это более интересная часть вашего вопроса:
SQL является строго типизированным языком, он не позволяет вычислять
integer
одно и то же выражение в одной строке иtext
в следующей. Но так как вас интересует толькоboolean
результат теста, вы можете обойти это ограничение с помощьюCASE
выражения, которое разветвляется в зависимости от результатаjsonb_typeof()
:Нетипизированный строковый литерал справа от
>
оператора автоматически приводится к соответствующему типу значения слева. Если вы поместите туда типизированное значение, тип должен совпадать или вы должны явным образом привести его - если в системе не зарегистрировано адекватное неявное приведение.Если вы знаете, что все числовые значения на самом деле
integer
, вы также можете:источник