Извлеките int, string, boolean и т. д. как соответствующий тип PostgreSQL из JSON
я чувствую, что мне просто не хватает чего-то простого здесь, но я просмотрел документацию PostgreSQL по JSON и операторам и функциям JSON и не вижу ничего, объясняющего это.
легко превратить вещи в JSON в PostgreSQL:
SELECT *, pg_typeof(j) FROM (VALUES
(to_json(5)),
(to_json(true)),
(to_json('foo'::TEXT))
) x (j);
вернет мне хороший набор результатов, полный json
s:
j | pg_typeof
-------+-----------
5 | json
true | json
"foo" | json
но как мне преобразовать эти json
значения назад в их первоначальные типы? Я не ожидал конечно, все это можно сделать в одном результирующем наборе, поскольку типы несовместимы. Я имею в виду индивидуально.
много чего я пробовал
кастинг, конечно, не работает:
SELECT to_json(5)::NUMERIC;
дает
ERROR: cannot cast type json to numeric
если я попытаюсь злоупотребить
3 ответов
самый простой способ для булевых и чисел, кажется, сначала бросить в TEXT
а затем приведите к соответствующему типу:
SELECT j::TEXT::NUMERIC
FROM (VALUES ('5.4575e6'::json)) x (j)
-- Result is 5457500, with column type NUMERIC
SELECT j::TEXT::BOOLEAN
FROM (VALUES ('true'::json)) x (j)
-- Result is t, with column type BOOLEAN
это оставляет строки, где вы вместо этого возвращаете цитируемое значение, пытаясь это:
SELECT j::TEXT
FROM (VALUES (to_json('foo'::TEXT))) x (j)
-- Result is "foo"
видимо, именно эта часть моего вопроса уже был рассмотрен. Вы можете обойти его, обернув текстовое значение в массив, а затем извлекая его:
SELECT array_to_json(array[j])->>0
FROM (VALUES (to_json('foo'::TEXT))) x (j)
-- Result is foo, with column type TEXT.
первый шаг: если ваши значения содержатся в структурах (что обычно имеет место), вам нужно использовать правильные операторы / функции для извлечения строкового представления ваших данных:->>
(9.3+), #>>
(9.3+), json_each_text()
(9.3+), json_array_elements_text()
(9.4+).
выбрать текстовое представление элементов массива JSON' в 9.3, вам нужно что-то вроде этого:
select json_array ->> indx
from generate_series(0, json_array_length(json_array) - 1) indx
для скалярных значений, вы можете использовать эту маленькую хитрость:
select ('[' || json_scalar || ']')::json ->> 0 -- ...
на данный момент, строки и nulls обрабатываются (JSON nulls преобразуются в sql NULL
s этими методами). Выберите цифры, вам нужно использовать слепки для numeric
(это полностью1 совместим с номером json). Выберите логические используйте муляжи boolean
(как true
и false
поддерживаются в качестве входных представлений). Но обратите внимание, что приведения могут привести к сбою запроса, если их входное представление не общепринятый. F. ex. если у вас есть объект json в некоторых из ваших столбцов, этот объект обычно имейте некоторый ключ, который обычно число (но не всегда), этот запрос может завершиться неудачно:
select (json_object ->> 'key')::numeric
from your_table
если у вас есть такие данные, вам нужно отфильтровать свой выбор с помощью json_typeof()
(9.4+):
select (json_object ->> 'key')::numeric
from your_table
where json_typeof(json_object -> 'key') = 'number'
1 я не проверил их полные синтаксисы, но numeric
также принимает научную нотацию, поэтому теоретически все номера json должны обрабатываться правильно.
для 9.2+ эта функция может проверить тип значения json:
create or replace function json_typeof(json)
returns text
language sql
immutable
strict
as $func$
select case left(trim(leading E'\x20\x09\x0A\x0D' from ::text), 1)
when 'n' then 'null'
when 't' then 'boolean'
when 'f' then 'boolean'
when '"' then 'string'
when '[' then 'array'
when '{' then 'object'
else 'number'
end
$func$;
это вопрос, похожий на ваш. по сути, базовые битовые представления типов данных несовместимы, и преобразование скаляра в собственный тип не является чем-то, что было реализовано из-за неоднозначности. JSON имеет очень строгую спецификацию, которая тесно соответствует объектам javascript и аборигенам.
возможно, но я не думаю, что это было реализовано.