Eu tenho uma coluna data
que contém um json
documento aproximadamente assim:
{
"name": "foo",
"tags": ["foo", "bar"]
}
Gostaria de transformar a tags
matriz aninhada em uma string concatenada ( foo, bar
). Isso seria facilmente possível com a array_to_string()
função na teoria. No entanto, essa função não atua em json
matrizes. Então, eu me pergunto como transformar essa json
matriz em um Postgres array
?
postgresql
postgresql-9.3
array
json
Christoph
fonte
fonte
json_extract_path_text(your_column, 'tags')
que você está procurando?Respostas:
Postgres 9.4 ou mais recente
Obviamente inspirado neste post , o Postgres 9.4 adicionou as funções ausentes:
Obrigado a Laurence Rowe pelo patch e Andrew Dunstan por cometer!
json_array_elements_text(json)
jsonb_array_elements_text(jsonb)
Desnaturar a matriz JSON. Em seguida, use
array_agg()
ou um construtor ARRAY para criar uma matriz do Postgres a partir dele. Oustring_agg()
para construir umatext
string .Agregue elementos não aninhados por linha em uma
LATERAL
subconsulta ou correlacionada. O pedido original é preservado e não precisamosORDER BY
,GROUP BY
nem mesmo uma chave exclusiva na consulta externa. Vejo:Substitua 'json' por 'jsonb'
jsonb
em todos os seguintes códigos SQL.Sintaxe curta:
Relacionado:
Construtor ARRAY na subconsulta correlacionada:
Relacionado:
Diferença sutil : os
null
elementos são preservados em matrizes reais . Isso não é possível nas consultas acima produzindo umatext
sequência que não pode conternull
valores. A representação verdadeira é uma matriz.Wrapper de função
Para uso repetido, para tornar isso ainda mais simples, encapsule a lógica em uma função:
Torne-a uma função SQL , para que possa ser incorporada em consultas maiores.
Faça isso
IMMUTABLE
(porque é) para evitar a avaliação repetida em consultas maiores e permita-o em expressões de índice.Ligar:
db <> mexer aqui
Postgres 9.3 ou anterior
Use a função
json_array_elements()
. Mas obtemos strings com aspas duplas .Consulta alternativa com agregação na consulta externa.
CROSS JOIN
remove linhas com matrizes ausentes ou vazias. Também pode ser útil para processar elementos. Precisamos de uma chave exclusiva para agregar:Construtor ARRAY, ainda com seqüências de caracteres citadas:
Observe que
null
é convertido para o valor do texto "nulo", diferente da acima. Incorreto, estritamente falando, e potencialmente ambíguo.O pobre homem não cita
trim()
:Recupere uma única linha de tbl:
Strings formam subconsulta correlacionada:
Construtor ARRAY:
SQL Fiddle original (desatualizado) .
db <> mexa aqui.
Relacionado:
Notas (desatualizadas desde a página 9.4)
Nós precisaríamos de um
json_array_elements_text(json)
, o gêmeo de,json_array_elements(json)
para retornartext
valores adequados de uma matriz JSON. Mas isso parece estar faltando no arsenal fornecido de funções JSON . Ou alguma outra função para extrair umtext
valor de umJSON
valor escalar . Parece que sinto falta também.Então eu improvisei com
trim()
, mas isso falhará em casos não triviais ...fonte
to_jsonb()
para conversão de array-> jsonb.SELECT ARRAY(SELECT json_array_elements_text(_js))
realmente garantir que a ordem da matriz é preservado? O otimizador não pode alterar teoricamente a ordem das linhas que saem de json_array_elements_text?PG 9.4+
A resposta aceita é definitivamente o que você precisa, mas por uma questão de simplicidade, aqui está um ajudante que eu uso para isso:
Então faça:
fonte
Esta pergunta foi feita nas listas de discussão do PostgreSQL e eu vim com essa maneira imprudente de converter texto JSON em tipo de texto PostgreSQL através do operador de extração de campo JSON:
Basicamente, ele converte o valor em uma matriz de elemento único e solicita o primeiro elemento.
Outra abordagem seria usar esse operador para extrair todos os campos um por um. Porém, para matrizes grandes, isso provavelmente é mais lento, pois precisa analisar toda a cadeia JSON de cada elemento da matriz, levando à complexidade de O (n ^ 2).
fonte
Eu testei algumas opções. Aqui está minha consulta favorita. Suponha que tenhamos uma tabela contendo o campo id e json. O campo json contém array, que queremos transformar em pg array.
Está funcionando em qualquer lugar e mais rápido que outros, mas parece mal-humorado)
Primeiro, o array json é convertido como texto e, em seguida, apenas trocamos colchetes entre parênteses. Finalmente, o texto está sendo convertido como uma matriz do tipo necessário.
e se você preferir matrizes de texto []
fonte
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"
Eu acho que você tem que adicionar alguma explicação sobre como isso deve funcionar.SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"
Não é tão à prova de bomba ...Essas poucas funções, tiradas das respostas a esta pergunta , são o que eu estou usando e elas estão funcionando muito bem
Em cada um deles, ao concatenar com uma matriz vazia, eles lidam com um caso que me atormentou um pouco, pois se você tentar lançar uma matriz vazia de
json
/jsonb
sem ela, não receberá nada de volta, em vez de um array vazio ({}
) como seria de esperar. Estou certo de que há alguma otimização para eles, mas eles são deixados para simplificar a explicação do conceito.fonte