Ustaw nazwy atrybutów podczas tworzenia JSON za pomocą row_to_json

24

Czy można zmienić nazwy domyślne f1, f2, f3...przy użyciu row_to_jsonfunkcji tylko dla niektórych kolumn?

potrafię

row_to_json(customers)

powracający

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

Ale jeśli chcę tylko nazwy bez id_customer, muszę użyć

row_to_json(row(first_name, last_name))

a potem dostaję

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

Chciałbym uzyskać ten wynik z domyślnymi nazwami kolumn lub własnymi. Wiem, że mogę stworzyć własny typ kompozytu i użyć go

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

ale czy nie można tego zrobić poprawnie w zapytaniu bez utworzenia tego typu?

boobiq
źródło
1
Zobacz także: odniesienie 1 i odniesienie 2 podobne
MikeM

Odpowiedzi:

17

Wspólne wyrażenie tabelowe pozwala jawnie określać aliasy, nie tylko dla CTE, ale dla jego kolumn.

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

Różni się to od przykładu @ dezso, ponieważ nie stosuje się go col AS aliasdla każdej kolumny na SELECTliście; aliasuje nazwy kolumn w aliasie tabeli CTE.

Użyłem VALUESwyrażenia jako podzapytania, ale możesz użyć SELECTdowolnego, co chcesz; Chodzi o to, że wszelkie aliasy kolumn, które są udostępniane lub zakładane w podzapytaniu, można zastąpić w definicji CTE, określając listę nazw kolumn.

Możesz zrobić to samo w podzapytaniu, ponownie zamiast używać AS alias:

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

To nie działa ROWbezpośrednio z wyrażeniem; możesz rzucić tylko ROWna konkretny typ, nie możesz go aliasować.

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
źródło
Czy jest jakaś różnica (oprócz stylu i / lub czytelności) między naszymi rozwiązaniami (użytkowanie, wydajność itp.)?
dezso
@dezso Nie, i prawdopodobnie powinienem właśnie opublikować komentarz. Przepraszam.
Craig Ringer
Myślę, że to jest OK. Poparłem nawet twoją odpowiedź, ponieważ zawiera przydatne informacje, których moja nie ma.
dezso,
Czy istnieje składnia dynamicznego pobierania aliasów kolumn? Wyciągam ze schematu EAV (wartość atrybutu bytu), w którym pożądane nazwy kluczy są również wybierane z kolumny attribute.name.
Chris
@Chris Potrzebujesz bardziej wyrafinowanych funkcji JSON w 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

zrobi co chcesz bez wpływu na wydajność (i nie jest zbyt gadatliwy):

  id  |   first_last                                |   age
------+---------------------------------------------+---------
  1   | {"fisrt_name": "John", "last_name": "Smit"} |   34
Anatolij Ressin
źródło
4
Ta odpowiedź to klejnot.
tiffon
Dziękuję bardzo, że uratowałeś moje popołudnie, szkoda, że ​​nie jest to cytowany przykład w interfejsie API PostgreSQL. Wiedziałem, że to możliwe
jlandercy
9

Możesz zrobić coś takiego:

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

(Oczywiście to samo można osiągnąć za pomocą

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

ale ten pierwszy był bardziej czytelny).

W WITHczęści możesz budować w locie rzędy dowolnej struktury.

dezso
źródło
Aby połączyć nie-jsonb z jsonb :: SELECT row_to_json (r. *) FROM (SELECT c1, c2 :: jsonb FROM us_ca_monterey_aoc.test) as r
Andrew Scott Evans
9

Możesz użyć 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
źródło