Establezca nombres en atributos al crear JSON con row_to_json

24

¿Es posible cambiar el nombre de los f1, f2, f3...nombres predeterminados cuando se usa la row_to_jsonfunción solo para algunas columnas?

puedo hacer

row_to_json(customers)

volviendo

{"id_customer":2,"first_name":"bla","last_name":"second_bla"}

Pero si solo quiero nombres sin id_customer, tengo que usar

row_to_json(row(first_name, last_name))

y luego me sale

{"f1":"bla","f2":"second_bla"}

Y me gustaría obtener este resultado con los nombres de columna predeterminados o con el mío. Sé que puedo crear mi propio tipo compuesto y usar

row_to_json(row(first_name, last_name))::my_custom_type

pero, ¿no es posible hacerlo bien en la consulta sin crear ese tipo?

boobiq
fuente
1
Ver también: referencia 1 y referencia 2 para similares
MikeM

Respuestas:

17

Una expresión de tabla común le permite especificar alias explícitamente, no solo para el CTE sino también para sus columnas.

WITH data(col1,col2,cola,colb) AS (
  VALUES (1,2,'fred','bob')
)
SELECT row_to_json(data) FROM data;

Esto es diferente al ejemplo de @ dezso en que no usa col AS alias para cada columna de una SELECTlista; alias los nombres de columna en el alias de la tabla CTE.

He usado un VALUES expresión como subconsulta, pero puedes usar SELECTlo que quieras; el punto es que cualquier alias de columna que se proporcione o se asuma en la subconsulta puede anularse en la definición de CTE especificando una lista de nombres de columna.

Puede hacer lo mismo en una subconsulta, de nuevo en lugar de usar AS alias:

SELECT row_to_json(data) 
FROM (VALUES (1,2,'fred','bob')) data(col1,col2,cola,colb);

Esto no funciona con una ROWexpresión directamente; solo puedes lanzar un ROWtipo concreto, no puedes usar alias.

regress=> SELECT ROW(1,2,'fred','bob') AS x(a,b,c,d);
ERROR:  syntax error at or near "("
LINE 1: SELECT ROW(1,2,'fred','bob') AS x(a,b,c,d);
Craig Ringer
fuente
¿Hay alguna diferencia (aparte del estilo y / o legibilidad) entre nuestras soluciones (uso, rendimiento, etc.)?
dezso
@dezso No, y probablemente debería haber publicado un comentario. Lo siento.
Craig Ringer
Creo que esto esta bien. Incluso voté por tu respuesta porque contiene información útil que la mía no contiene.
dezso
¿Existe una sintaxis para obtener dinámicamente los alias de columna? Extraigo de un esquema EAV (valor de atributo de entidad) donde los nombres de clave deseados también se seleccionan de la columna atributo.nombre.
Chris
@Chris Necesitarás las funciones json más sofisticadas en 9.4.
Craig Ringer
23
select 
   c.id,
   (select row_to_json(_) from (select c.first_name, c.last_name) as _) as first_last,
   c.age
from
   customers as c

hará lo que quiera sin ningún impacto en el rendimiento (y no es demasiado detallado):

  id  |   first_last                                |   age
------+---------------------------------------------+---------
  1   | {"fisrt_name": "John", "last_name": "Smit"} |   34
Anatoly Ressin
fuente
44
Esta respuesta es una joya.
tiffon
Muchas gracias por salvarme la tarde, lástima que este no sea un ejemplo citado en la API de PostgreSQL. Sabía que era posible
jlandercy
9

Puedes hacer algo como esto:

WITH r AS (
  SELECT 'bla' AS name1, 'otherbla' AS name2
)
SELECT row_to_json(r.*)
FROM r
;

(Por supuesto, lo mismo se puede lograr con

SELECT row_to_json(r.*)
FROM (SELECT 'bla' AS name1, 'otherbla' AS name2) r
;

pero encontré el primero más legible).

En la WITHparte puedes construir filas de cualquier estructura sobre la marcha.

dezso
fuente
Para concatenar non-jsonb con jsonb :: SELECT row_to_json (r. *) FROM (SELECT c1, c2 :: jsonb FROM us_ca_monterey_aoc.test) como r
Andrew Scott Evans
9

Puedes usar json_build_object.

SELECT 
  json_build_object('id', data.customer_id, 'first_name', data.first_name, 'last_name', data.last_name) as your_json
FROM data;
aheuermann
fuente