Как преобразовать тип PostgreSQL 9.4 jsonb в float

Я пробую следующий запрос:

SELECT (json_data->'position'->'lat') + 1.0 AS lat FROM updates LIMIT 5;

(+1.0 именно там, чтобы принудительно преобразовать в float. Мои актуальные запросы намного сложнее, этот запрос является всего лишь тестовым случаем для проблемы.)

Я получаю сообщение об ошибке:

ERROR:  operator does not exist: jsonb + numeric

Если я добавляю в явное литье:

SELECT (json_data->'position'->'lat')::float + 1.0 AS lat FROM updates LIMIT 5;

ошибка становится:

ERROR:  operator does not exist: jsonb + double precesion

Я понимаю, что большинство значений jsonb нельзя вставлять в float, но в этом случае я знаю, что lats - все JSON-номера.

Есть ли функция, которая переводит значения jsonb в float (или возвращает NULL для uncastable)?

Ответ 1

Есть две операции для получения значения из JSON. Первая -> вернет JSON. Второй ->> будет возвращать текст.

Подробности: Функции и операторы JSON

Попробуйте

SELECT (json_data->'position'->>'lat')::float + 1.0 AS lat
FROM updates
LIMIT 5

Ответ 2

В документации есть также функции

jsonb_populate_record()
jsonb_populate_recordset()

Аналог их близнецов json (присутствует с pg 9.3)

json_populate_record()
json_populate_recordset()

Вам нужен предопределенный тип строки. Либо используйте тип строки существующей таблицы, либо укажите ее с помощью CREATE TYPE. Или замените временную таблицу ad hoc:

CREATE TEMP TABLE x(lat float);

Может быть один столбец или длинный список столбцов.

Только те столбцы заполнены, где имя соответствует клавише в объекте json. Значение принудительно применяется к столбцу type и должно быть совместимым или создается исключение. Другие ключи игнорируются.

SELECT lat + 1  -- no need for 1.0, this is float already
FROM   updates u
     , jsonb_populate_record(NULL::x, u.json_data->'position')
LIMIT  5;

Используя неявный LATERAL JOIN здесь.

Аналогично, используйте jsonb_populate_recordset() для разложения массивов на несколько строк для каждой записи.

Это работает аналогично в Postgres 9.3 с json. Существует дополнительное преимущество, заключающееся в том, что литье в/из text внутренне не требуется для числовых данных в jsonb.

Ответ 3

AFAIK там нет json- > float casting в Postgres, поэтому вы можете попробовать явный (json_data->'position'->'lat')::text::float cast

Ответ 4

Вы должны передать значение json в текст и затем плавать.

Попробуйте следующее:

(json_data #>> '{field}')::float