2017-02-14 13 views
3

完全に構造化されたJSONクエリの結果として取得する必要があります。 私はポストグルで有用かもしれないいくつかの組み込み関数があることがわかります。次のように私は構造を作成した例としてsql query postgresからネストされたjsonを作成する9.4

-- Table: person 

-- DROP TABLE person; 

CREATE TABLE person 
(
    id integer NOT NULL, 
    name character varying(30), 
    CONSTRAINT person_pk PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE person 
    OWNER TO postgres; 

    -- Table: car 

-- DROP TABLE car; 

CREATE TABLE car 
(
    id integer NOT NULL, 
    type character varying(30), 
    personid integer, 
    CONSTRAINT car_pk PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE car 
    OWNER TO postgres; 

    -- Table: wheel 

-- DROP TABLE wheel; 

CREATE TABLE wheel 
(
    id integer NOT NULL, 
    whichone character varying(30), 
    serialnumber integer, 
    carid integer, 
    CONSTRAINT "Wheel_PK" PRIMARY KEY (id) 
) 
WITH (
    OIDS=FALSE 
); 
ALTER TABLE wheel 
    OWNER TO postgres; 

そして、いくつかのデータ:

INSERT INTO person(id, name) 
VALUES (1, 'Johny'), 
     (2, 'Freddy'); 

INSERT INTO car(id, type, personid) 
VALUES (1, 'Toyota', 1), 
     (2, 'Fiat', 1),  
     (3, 'Opel', 2);  

INSERT INTO wheel(id, whichone, serialnumber, carid) 
VALUES (1, 'front', '11', 1), 
     (2, 'back', '12', 1), 
     (3, 'front', '21', 2), 
     (4, 'back', '22', 2), 
     (5, 'front', '3', 3); 

私は人のリストを含んでいるでしょう1つのJSONオブジェクトを持っていると思いますその結果、それぞれの人は車のリストと車の各車のリストを持っています。

私はそのような何かをしようとしたが、それは私が欲しい何かイマイチ:私はでとjson_aggいくつかのグループが欠けているが、私はこれを行うするかどうかはわかりませんと仮定し

select json_build_object(
    'Persons', json_build_object(
    'person_name', person.name, 
    'cars', json_build_object(
     'carid', car.id,  
     'type', car.type, 
     'comment', 'nice car', -- this is constant 
     'wheels', json_build_object(
      'which', wheel.whichone, 
      'serial number', wheel.serialnumber 
     ) 

    )) 
) 

from 
person 
left join car on car.personid = person.id 
left join wheel on wheel.carid = car.id 

を。

私はこのような結果何かとして持っているしたいと思います:

{ "persons": [ 
    { 
     "person_name": "Johny", 
     "cars": [ 
      { 
      "carid": 1, 
      "type": "Toyota", 
      "comment": "nice car", 
      "wheels": [{ 
       "which": "Front", 
       "serial number": 11 
      }, 
      { 
       "which": "Back", 
       "serial number": 12 
      }] 
      }, 
      { 
      "carid": 2, 
      "type": "Fiat", 
      "comment": "nice car", 
      "wheels": [{ 
       "which": "Front", 
       "serial number": 21 
      },{ 
       "which": "Back", 
       "serial number": 22 
      }] 
      } 
     ] 
    }, 
    { 
     "person_name": "Freddy", 
     "cars": [ 
      { 
      "carid": 3, 
      "type": "Opel", 
      "comment": "nice car", 
      "wheels": [{ 
       "which": "Front", 
       "serial number": 33 
      }] 
      }] 
    }] 
} 

http://www.jsoneditoronline.org/?id=7792a0a2bf11be724c29bb86c4b14577

+0

@a_horse_with_no_name done – Snorlax

答えて

3

あなたは結果として、階層構造を取得するために、階層クエリを構築する必要があります。

単一のjsonオブジェクトに多くの人物を配置したいので、json_agg()を使用してjson配列の人を集めます。 同様に、人は複数の車を所有することができ、1人の人に属する車をjsonアレイに配置する必要があります。車と車輪にも同じことが言えます。

select 
    json_build_object(
     'persons', json_agg(
      json_build_object(
       'person_name', p.name, 
       'cars', cars 
      ) 
     ) 
    ) persons 
from person p 
left join (
    select 
     personid, 
     json_agg(
      json_build_object(
       'carid', c.id,  
       'type', c.type, 
       'comment', 'nice car', -- this is constant 
       'wheels', wheels 
       ) 
      ) cars 
    from 
     car c 
     left join (
      select 
       carid, 
       json_agg(
        json_build_object(
         'which', w.whichone, 
         'serial number', w.serialnumber 
        ) 
       ) wheels 
      from wheel w 
      group by 1 
     ) w on c.id = w.carid 
    group by personid 
) c on p.id = c.personid; 

(フォーマット済み)結果:

{ 
    "persons": [ 
     { 
      "person_name": "Johny", 
      "cars": [ 
       { 
        "carid": 1, 
        "type": "Toyota", 
        "comment": "nice car", 
        "wheels": [ 
         { 
          "which": "front", 
          "serial number": 11 
         }, 
         { 
          "which": "back", 
          "serial number": 12 
         } 
        ] 
       }, 
       { 
        "carid": 2, 
        "type": "Fiat", 
        "comment": "nice car", 
        "wheels": [ 
         { 
          "which": "front", 
          "serial number": 21 
         }, 
         { 
          "which": "back", 
          "serial number": 22 
         } 
        ] 
       } 
      ] 
     }, 
     { 
      "person_name": "Freddy", 
      "cars": [ 
       { 
        "carid": 3, 
        "type": "Opel", 
        "comment": "nice car", 
        "wheels": [ 
         { 
          "which": "front", 
          "serial number": 3 
         } 
        ] 
       } 
      ] 
     } 
    ] 
} 

あなたが共通テーブル式を使用することができネストされた派生テーブルに精通していない場合。 この変形は最高レベルに向けて最もネストされたオブジェクトから始めて、クエリを構築する必要があることを示しています。私は、このソリューションを作ってみた

with wheels as (
    select 
     carid, 
     json_agg(
      json_build_object(
       'which', w.whichone, 
       'serial number', w.serialnumber 
      ) 
     ) wheels 
    from wheel w 
    group by 1 
), 
cars as (
    select 
     personid, 
     json_agg(
      json_build_object(
       'carid', c.id,  
       'type', c.type, 
       'comment', 'nice car', -- this is constant 
       'wheels', wheels 
       ) 
      ) cars 
    from car c 
    left join wheels w on c.id = w.carid 
    group by c.personid 
) 
select 
    json_build_object(
     'persons', json_agg(
      json_build_object(
       'person_name', p.name, 
       'cars', cars 
      ) 
     ) 
    ) persons 
from person p 
left join cars c on p.id = c.personid; 
+0

結果をデータベースの最初の10人に限定したい場合はどうすればよいですか? – Snorlax

+1

'person'を派生テーブルで置き換えるべきです。つまり' from person p'の代わりに 'from(select * from person ... limit 10)p'を使います。 – klin

+0

パーフェクト!そして、もう1つのこと、すべての人がただ1台の車しか持っていないと確信していれば、オブジェクトの配列を表示したいが結果jsonにオブジェクトを表示したくないのですか?どのように簡単にそれを変更するには? – Snorlax

3

。それは非常にコンパクトであり、どんな場合でも動作します。 ただし、他のソリューションと比較したときのパフォーマンスへの影響は、json_build_objectを多く使用するものと比較するとわかりません。 row_to_jsonjson_build_objectに使用する利点は、すべての作業がフードの下で行われることで、クエリが読みやすくなります。

SELECT json_build_object('persons', json_agg(p)) persons 
FROM (
     SELECT 
     person.name person_name, 
     (
      SELECT json_agg(row_to_json(c)) 
      FROM (
        SELECT 
        id carid, 
        type, 
        (
         SELECT json_agg(row_to_json(w)) 
         FROM (
          SELECT 
           whichone which, 
           serialnumber 
          FROM wheel 
          WHERE wheel.carid = car.id 
          ) w 
        ) wheels 
        FROM car 
        WHERE car.personid = person.id 
       ) c 
     ) AS  cars 
     FROM person 
) p 
+0

また、車に0または1のエンジンが搭載されているとします。どのようにオブジェクトの配列ではないオブジェクトとしてそれを入れ子にする? – Snorlax

+1

次に、副選択のホイールの隣にエンジンを追加し、to_json関数を使ってjsonに変換します。 SELECT json_build_object( 'persons'、json_agg(p))人FROM(SELECT person.name person_name、SELECT json_agg(row_to_json(c))FROM(SELECT id carid、type、(SELECT to_json(e)FROM(SELECT馬力FROMエンジン)ここで、engine.carid = car.id)e)エンジン、(SELECT json_agg(row_to_json(w))FROM(FROMホイールWHERE wheel.carid = car.id)w)ホイールFROM car WHERE car.personid = person .id)c)ASからの人車)p –

関連する問題