Tengo una columna data
que contiene un json
documento más o menos así:
{
"name": "foo",
"tags": ["foo", "bar"]
}
Me gustaría convertir la tags
matriz anidada en una cadena concatenada ( foo, bar
). Eso sería fácilmente posible con la array_to_string()
función en teoría. Sin embargo, esta función no actúa en json
matrices. ¿Entonces me pregunto cómo convertir esta json
matriz en un Postgres array
?
postgresql
postgresql-9.3
array
json
Christoph
fuente
fuente
json_extract_path_text(your_column, 'tags')
lo que estás buscando?Respuestas:
Postgres 9.4 o más reciente
Obviamente inspirado en esta publicación , Postgres 9.4 agregó las funciones que faltan: ¡
Gracias a Laurence Rowe por el parche y a Andrew Dunstan por comprometerse!
json_array_elements_text(json)
jsonb_array_elements_text(jsonb)
Para deshacer la matriz JSON. Luego use
array_agg()
o un constructor ARRAY para construir una matriz Postgres a partir de él. Ostring_agg()
para construir unatext
cadena .Agregue elementos no anidados por fila en una
LATERAL
subconsulta correlacionada. Luego se conserva el orden original y no necesitamosORDER BY
,GROUP BY
ni siquiera una clave única en la consulta externa. Ver:Reemplace 'json' con 'jsonb'
jsonb
en todos los siguientes códigos SQL.Sintaxis corta:
Relacionado:
ARRAY constructor en subconsulta correlacionada:
Relacionado:
Diferencia sutil : los
null
elementos se conservan en matrices reales . Esto no es posible en las consultas anteriores que producen unatext
cadena, que no puede contenernull
valores. La verdadera representación es una matriz.Envoltorio de funciones
Para uso repetido, para hacer esto aún más simple, encapsule la lógica en una función:
Lo convierten en una función SQL , para que pueda ser inline en las consultas más grandes.
Hágalo
IMMUTABLE
(porque lo es) para evitar evaluaciones repetidas en consultas más grandes y permitirlo en expresiones de índice.Llamada:
db <> violín aquí
Postgres 9.3 o anterior
Usa la función
json_array_elements()
. Pero obtenemos cadenas dobles entre comillas .Consulta alternativa con agregación en la consulta externa.
CROSS JOIN
elimina filas con matrices faltantes o vacías. También puede ser útil para procesar elementos. Necesitamos una clave única para agregar:ARRAY constructor, todavía con cadenas citadas:
Tenga en cuenta que
null
se convierte en el valor de texto "nulo", a diferencia de lo anterior. Incorrecto, estrictamente hablando, y potencialmente ambiguo.Pobre hombre citando con
trim()
:Recupere una sola fila de tbl:
Las cadenas forman una subconsulta correlacionada:
ARRAY constructor:
Fiddle SQL original (obsoleto) .
db <> violín aquí.
Relacionado:
Notas (desactualizadas desde la página 9.4)
Necesitaríamos un
json_array_elements_text(json)
, el gemelo dejson_array_elements(json)
para devolvertext
valores adecuados de una matriz JSON. Pero eso parece faltar en el arsenal provisto de funciones JSON . O alguna otra función para extraer untext
valor de unJSON
valor escalar . Parece que me estoy perdiendo ese también.Así que improvisé
trim()
, pero eso fallará en casos no triviales ...fuente
to_jsonb()
usarías para la conversión de matriz-> jsonb.SELECT ARRAY(SELECT json_array_elements_text(_js))
Realmente garantiza que se conserva el orden de la matriz? ¿No se le permite al optimizador alterar teóricamente el orden de las filas que salen de json_array_elements_text?PG 9.4+
La respuesta aceptada es definitivamente lo que necesita, pero por simplicidad, aquí hay una ayuda que uso para esto:
Entonces solo haz:
fuente
Esta pregunta se hizo en las listas de correo de PostgreSQL y se me ocurrió esta forma hack de convertir texto JSON a tipo de texto PostgreSQL a través del operador de extracción de campo JSON:
Básicamente, convierte el valor en una matriz de un solo elemento y luego solicita el primer elemento.
Otro enfoque sería utilizar este operador para extraer todos los campos uno por uno. Pero para matrices grandes esto es probablemente más lento, ya que necesita analizar toda la cadena JSON para cada elemento de la matriz, lo que lleva a una complejidad O (n ^ 2).
fuente
He probado algunas opciones. Aquí está mi consulta favorita. Supongamos que tenemos una tabla que contiene id y campo json. El campo json contiene una matriz, que queremos convertir en matriz pg.
Funciona en cualquier lugar y más rápido que otros, pero parece muuuuuuuuuuy)
Primero, la matriz json se convierte como texto, y luego solo cambiamos los corchetes por paréntesis. Finalmente, el texto se está convirtiendo en una matriz del tipo requerido.
y si prefieres las matrices de texto []
fuente
SELECT TRANSLATE('{"name": "foo", "tags": ["foo", "bar"]}'::jsonb::text, '[]','{}')::INT[]; ERROR: malformed array literal: "{"name": "foo", "tags": {"foo", "bar"}}"
Creo que tienes que agregar alguna explicación sobre cómo se supone que funciona.SELECT translate('["foo", "bar"]'::jsonb::text, '[]','{}')::INT[]; ERROR: invalid input syntax for integer: "foo"
No es tan a prueba de bombas ...Estas pocas funciones, tomadas de las respuestas a esta pregunta , son lo que estoy usando y están funcionando muy bien
En cada uno de ellos, al concatenar con una matriz vacía, manejan un caso que me hizo aturdir mi cerebro por un momento, en el que si intentas lanzar una matriz vacía desde
json
/jsonb
sin ella no obtendrás nada, en lugar de un matriz vacía ({}
) como cabría esperar. Estoy seguro de que hay algo de optimización para ellos, pero se dejan como es para simplificar la explicación del concepto.fuente