JSONB를 사용하여 PostgreSQL 가입


16

나는이 SQL을 가지고있다 :

CREATE TABLE test(id SERIAL PRIMARY KEY, data JSONB);

INSERT INTO test(data) VALUES
   ('{"parent":null,"children":[2,3]}'),
   ('{"parent":1,   "children":[4,5]}'),
   ('{"parent":1,   "children":[]}'),
   ('{"parent":2,   "children":[]}'),
   ('{"parent":2,   "children":[]}');

그것은 줄 것이다 :

 id |                 data                 
----+--------------------------------------
  1 | {"parent": null, "children": [2, 3]}
  2 | {"parent": 1, "children": [4, 5]}
  3 | {"parent": 1, "children": []}
  4 | {"parent": 2, "children": []}
  5 | {"parent": 2, "children": []}

정상적인 일대 다를 수행하면 다음과 같이 표시됩니다.

SELECT * 
FROM test x1
  LEFT JOIN test x2
    ON x1.id = (x2.data->>'parent')::INT;
 id |                 data                 | id |               data                
----+--------------------------------------+----+-----------------------------------
  1 | {"parent": null, "children": [2, 3]} |  2 | {"parent": 1, "children": [4, 5]}
  1 | {"parent": null, "children": [2, 3]} |  3 | {"parent": 1, "children": []}
  2 | {"parent": 1, "children": [4, 5]}    |  4 | {"parent": 2, "children": []}
  2 | {"parent": 1, "children": [4, 5]}    |  5 | {"parent": 2, "children": []}
  5 | {"parent": 2, "children": []}        |    | 
  4 | {"parent": 2, "children": []}        |    | 
  3 | {"parent": 1, "children": []}        |    | 

어린이를 기준으로 가입하는 방법 ( LEFT JOIN또는 사용 WHERE IN)? 난 노력 했어:

SELECT data->>'children' FROM test;
 ?column? 
----------
 [2, 3]
 [4, 5]
 []
 []
 []

SELECT json_array_elements((data->>'children')::TEXT) FROM t...
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

SELECT json_array_elements((data->>'children')::JSONB) FROM ...
               ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.

SELECT json_to_record((data->>'children')::JSON) FROM test;
ERROR:  function returning record called in context that cannot accept type record
HINT:  Try calling the function in the FROM clause using a column definition list.

SELECT * FROM json_to_record((test.data->>'children')::JSON);
ERROR:  missing FROM-clause entry for table "test"
LINE 1: SELECT * FROM json_to_record((test.data->>'children')::JSON)...

답변:


23

이것은 더 효율적입니다.

부착 jsonjson_array_elements()PG 9.3

SELECT p.id AS p_id, p.data AS p_data
     , c.id AS c_id, c.data AS c_data
FROM   test p
LEFT   JOIN LATERAL json_array_elements(p.data->'children') pc(child) ON TRUE
LEFT   JOIN test c ON c.id = pc.child::text::int;
  • 에 대한 참조 ->대신 연산자를 사용하십시오 . 당신이 가진 방식으로, 당신은 먼저 캐스트 / 로 갔다가 다시 돌아옵니다 .->>childrenjsonjsonbtextjson

  • set-returning 함수를 호출하는 확실한 방법은 LEFT [OUTER] JOIN LATERAL입니다. 여기 에는 자식 이 없는 행 이 포함됩니다 . 이를 제외 하려면 쉼표 를 사용하여 [INNER] JOIN LATERAL또는 CROSS JOIN-또는 속기 구문으로 변경하십시오.

    , json_array_elements(p.data->'children') pc(child)
  • 결과적으로 중복 열 이름을 피하십시오.

SQL 바이올린.

부착 jsonbjsonb_array_elements()PG 9.4

EXPLAIN 
SELECT p.id AS p_id, p.data AS p_data
     , c.id AS c_id, c.data AS c_data
FROM   test p
LEFT   JOIN LATERAL jsonb_array_elements(p.data->'children') pc(child) ON TRUE
LEFT   JOIN test c ON c.id = pc.child::text::int;
-------------------------------------------------------------------------------------------
 Hash Left Join  (cost=37.69..4826.24 rows=123000 width=72)
   Hash Cond: (((pc.child)::text)::integer = c.id)
   ->  Nested Loop Left Join  (cost=0.01..2482.31 rows=123000 width=68)
         ->  Seq Scan on test p  (cost=0.00..22.30 rows=1230 width=36)
         ->  Function Scan on jsonb_array_elements pc  (cost=0.01..1.01 rows=100 width=32)
   ->  Hash  (cost=22.30..22.30 rows=1230 width=36)
         ->  Seq Scan on test c  (cost=0.00..22.30 rows=1230 width=36)

제외 : A는 것이 기본 데이터 유형과 DB 설계를 표준화 방법 이 더 효율적입니다.


9.4rc1에 다음을 제공합니다.LINE 4: LEFT JOIN LATERAL json_array_elements(p.data->'children') ... ^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Kokizzu

^시작 부분json_array_elements
Kokizzu

1
아 내 나쁜, jsonb_대신 json_기능을 사용해야 합니다
Kokizzu

3

신경 쓰지 마, 길을 찾았 어

SELECT *
 FROM ( SELECT *, json_array_elements((data->>'children')::JSON) child FROM test) x1
   LEFT JOIN test x2
    ON x1.child::TEXT::INT = x2.id
;

 id |                 data                 | child | id |               data
----+--------------------------------------+-------+----+-----------------------------------
  1 | {"parent": null, "children": [2, 3]} | 2     |  2 | {"parent": 1, "children": [4, 5]}
  1 | {"parent": null, "children": [2, 3]} | 3     |  3 | {"parent": 1, "children": []}
  2 | {"parent": 1, "children": [4, 5]}    | 4     |  4 | {"parent": 2, "children": []}
  2 | {"parent": 1, "children": [4, 5]}    | 5     |  5 | {"parent": 2, "children": []}

                                                QUERY PLAN                                                 
-----------------------------------------------------------------------------------------------------------
 Hash Left Join  (cost=37.67..4217.38 rows=123000 width=104)
   Hash Cond: ((((json_array_elements(((test.data ->> 'children'::text))::json)))::text)::integer = x2.id)
   ->  Seq Scan on test  (cost=0.00..643.45 rows=123000 width=36)
   ->  Hash  (cost=22.30..22.30 rows=1230 width=36)
         ->  Seq Scan on test x2  (cost=0.00..22.30 rows=1230 width=36)

또는

SELECT *
 FROM test x1
    LEFT JOIN ( SELECT *, json_array_elements((data->>'children')::JSON) child FROM test) x2
    ON x1.id = x2.child::TEXT::INT
;

 id |                 data                 | id |                 data                 | child 
----+--------------------------------------+----+--------------------------------------+-------
  2 | {"parent": 1, "children": [4, 5]}    |  1 | {"parent": null, "children": [2, 3]} | 2
  3 | {"parent": 1, "children": []}        |  1 | {"parent": null, "children": [2, 3]} | 3
  4 | {"parent": 2, "children": []}        |  2 | {"parent": 1, "children": [4, 5]}    | 4
  5 | {"parent": 2, "children": []}        |  2 | {"parent": 1, "children": [4, 5]}    | 5
  1 | {"parent": null, "children": [2, 3]} |    |                                      | 

                                                QUERY PLAN                                                 
-----------------------------------------------------------------------------------------------------------
 Hash Right Join  (cost=37.67..4217.38 rows=123000 width=104)
   Hash Cond: ((((json_array_elements(((test.data ->> 'children'::text))::json)))::text)::integer = x1.id)
   ->  Seq Scan on test  (cost=0.00..643.45 rows=123000 width=36)
   ->  Hash  (cost=22.30..22.30 rows=1230 width=36)
         ->  Seq Scan on test x1  (cost=0.00..22.30 rows=1230 width=36)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.