json_agg 내부의 열을 선택하십시오.


21

다음과 같은 쿼리가 있습니다.

SELECT a.id, a.name, json_agg(b.*) as "item"
  FROM a
  JOIN b ON b.item_id = a.id
 GROUP BY a.id, a.name;

JSON 객체에 b없는 열을 선택하려면 어떻게 해야 b.item_id합니까?

에 대해 읽었 ROW지만 다음과 같은 JSON 객체를 반환합니다.

{"f1": "Foo", "f2": "Bar"}

적절한 열 키와 일치하도록 JSON 객체를 가져온 후에는 JSON 객체를 다시 매핑해야합니다. 나는 그것을 피하고 원래의 열 이름을 유지하고 싶습니다.

답변:


50

불행히도 SQL 구문에는 "이 하나의 열을 제외한 모든 열" 을 말하는 규정이 없습니다 . 행 유형 표현식 에서 나머지 열 목록을 철자하여 목표를 달성 할 수 있습니다 .

SELECT a.id, a.name
     , json_agg((b.col1, b.col2, b.col3)) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

보다 명확한 형식은 짧습니다 . ROW(b.col1, b.col2, b.col3)

그러나 열 이름 은 행 유형 표현식에서 유지되지 않습니다. 이런 식으로 JSON 객체에서 일반 키 이름을 얻습니다. 원래 열 이름을 유지하는 세 가지 옵션이 있습니다.

1. 등록 된 유형으로 캐스트

잘 알려진 (등록 된) 행 유형으로 캐스트합니다. 유형은 기존의 모든 테이블 또는 뷰에 대해 또는 명시적인 CREATE TYPE명령문으로 등록됩니다. 임시 솔루션에 임시 테이블을 사용할 수 있습니다 (세션 기간 동안 지속됨).

CREATE TEMP TABLE x (col1 int, col2 text, col3 date);  -- use adequate data types!

SELECT a.id, a.name
     , json_agg((b.col1, b.col2, b.col3)::x) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

2. 부속 선택을 사용하십시오

subselect를 사용하여 파생 테이블 을 구성하고 테이블 전체를 참조하십시오 . 이것은 또한 열 이름을 전달합니다. 더 장황하지만 등록 된 유형이 필요하지 않습니다.

SELECT a.id, a.name
     , json_agg((SELECT x FROM (SELECT b.col1, b.col2, b.col3) AS x)) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

3. json_build_object()포스트 그레스 9.4 이상

SELECT a.id, a.name
     , json_agg(json_build_object('col1', b.col1, 'col2', b.col2, 'col3', b.col3)) AS item
FROM   a
JOIN   b ON b.item_id = a.id
GROUP  BY a.id, a.name;

관련 :

jsonb각 기능 jsonb_agg()과 유사합니다 jsonb_build_object().

들어 포스트 그레스 9.5 도 참조 이상 a_horse의 답변을 새로운 짧은 구문 변종 : 포스트 그레스 추가 된 마이너스 연산자 -에 대한jsonb 대답 "이 하나의 키를 제외한 모든 키를" .
이후 포스트 그레스 10 "여러 개의 키를 제외한" 동일한 조작 복용 구현 text[]2 피연산자 - MLT는 주석 등을들 수있다.


1
> 또는 여러 키 json (b) -text []는 10부터 시작하여 사용할 수 있습니다.
mlt

솔루션 3은 나를 위해 매력처럼 작동했습니다!
루이스 페르난도 다 실바

17

9.6부터 간단히 -JSONB에서 키를 제거하는 데 사용할 수 있습니다 .

SELECT a.id, a.name, jsonb_agg(to_jsonb(b) - 'item_id') as "item"
FROM a
  JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;

to_jsonb(b)전체 행을 변환 한 - 'item_id'다음 item_id그 결과가 집계 된 이름으로 키를 제거합니다 .


이 새로운 기능은 OP가 기대했던 것 같습니다. 내 답변에 대한 링크를 추가했습니다.
Erwin Brandstetter

하위 선택 변형을 시도했을 때 json_agg함수 와 관련된 오류가 발생했습니다 .function json_agg(record) does not exist
fraxture

@fraxture : 그러면 Postgres 9.6을 사용하지 않습니다
a_horse_with_no_name

실제로 그것은 문제였습니다. v9.2에서 열을 필터링하는 방법이 있습니까?
fraxture

8

하위 쿼리를 사용하여 그룹별로 그룹화하지 않고 실제로 할 수 있습니다.

SELECT 
  a.id, a.name, 
  ( 
    SELECT json_agg(item)
    FROM (
      SELECT b.c1 AS x, b.c2 AS y 
      FROM b WHERE b.item_id = a.id
    ) item
  ) AS items
FROM a;

보고

{
  id: 1,
  name: "thing one",
  items:[
    { x: "child1", y: "child1 col2"},
    { x: "child2", y: "child2 col2"}
  ]
}

John Atten의이 기사 는 정말 흥미롭고 자세한 내용이 있습니다.


2

JSON을 만든 다음 집계하는 것이 가장 좋습니다. 예 :

with base as (
select a, b, ('{"ecks":"' || to_json(x) || '","wai":"' || to_json(y) || '","zee":"' || to_json(z) || '"}"')::json c
) select (a, b, array_to_json(array_agg(c)) as c)

CTE가 마음에 들지 않거나 사용으로 인해 성능 문제가있는 경우 하위 쿼리로 수행 할 수 있습니다.

또한이 작업을 많이 수행하려면 키-값 쌍을 래핑하는 함수를 만들어 코드가 더 깨끗해 보일 수 있습니다. 예를 들어 함수를 전달 'ecks', 'x'하면이 반환 "ecks": "x"됩니다.


1

1 비트를 제외한 모든 열 선택에 대해 아무것도 할 방법 json_agg(to_json(b.col_1, b.col_2, b.col_3 ...))이 없지만 각각 형식으로 json의 json 배열을 얻는 데 사용할 수 있습니다 {"col_1":"col_1 value", ...}.

따라서 쿼리는 다음과 같습니다.

SELECT a.id, a.name, json_agg(to_json(b.col_1,b.col_2,b.col_3...)) as item
  FROM a
  JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;

행을 다음과 같이 반환합니다.

id, name, item
8, the_name, [{"col_1":"value_1","col_2":"value_2","col_3":"value_3"...}, {"col_1":"value_1.2","col_2":"value_2.2","col_3":"value_3.2"...},...]
9, the_next_name, [{"col_1":"value_1.3","col_2":"value_2.3","col_3":"value_3.3"...},   {"col_1":"value_1.4","col_2":"value_2.4","col_3":"value_3.4"...},...]
...

(현재 Postgres 9.5.3을 사용하고 있으며이 지원이 언제 추가되었는지 100 % 확실하지 않습니다.)


1

당신이 사용할 수있는 json_build_object다음과 같은

SELECT 
  a.id, 
  a.name,
  json_agg(json_build_object('col1', b.col1, 'col2', b.col2) AS item
FROM a
JOIN b ON b.item_id = a.id
GROUP BY a.id, a.name;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.