2016-10-18 8 views
2

私はpostgresデータベースにいくつかのテーブルを一緒に参加させており、右結合テーブルの値を左結合テーブルの集約JSON構造として返します。しかし、私はそのクエリは、より多くのテーブルが結合される複雑になることがわかります。例えば:私はここに3つのテーブルに参加した非常に複雑なインデントされたクエリを書くことなく、深く入れ子になったJSON構造を作成する簡単な方法は何ですか?

select row_to_json(output) 
from (
    select image_type.name, 
    (
     select json_agg(instances) 
     from (
      select image_instance.name, (
       select json_agg(versions) 
       from (
        select image_version.name 
        from image_version 
        where image_version.image_instance_id = image_version.image_instance_id 
       ) versions 
      ) AS versions 
      from image_instance 
      where image_instance.image_type_id = image_type.image_type_id 
     ) instances 
    ) AS images 
    from image_type 
) output; 

、しかし、私はこれまでより多くのいくつかのテーブルを追加したいのですが、コードはすぐに扱いにくく、維持するのは難しいとなります。これらの種類の集約された結合を生成する簡単な方法はありますか?

+0

@a_horse_with_no_nameこれを拡張できますか?あなたが参照した記事を読んだが、私のデータはJSONブロブではなく正規化されたテーブルに保存されている。私はこれらのテーブルからJSON本体を生成したいだけです。おそらくあなたがもう少し拡大することができれば、それは私の理解を助けるでしょう。 –

答えて

1

まず、JSONは複数のテーブルのデータを結合するときの通常のフィールドと変わりません。物事は非常に迅速に複雑になる可能性があります。管理しやすいものを維持するためにいくつかのテクニックは、しかし、があります。

1.デイジーチェーン機能

は、それぞれ独立して機能からの出力を処理する必要はありません、あなたはように、1つの関数からの出力を供給することができます1つのステートメントで次への入力。あなたの例では、これは集計レベルごとにレベルの下位選択を失うことを意味し、エイリアスを忘れる可能性があります。あなたの例では、次のようになります。

select row_to_json(row(image_type.name, (
     select json_agg(image_instance.name, (
       select json_agg(image_version.name) 
       from image_version 
       where image_version.image_instance_id = image_instance.id) -- join edited 
     from image_instance 
     where image_instance.image_type_id = image_type.image_type_id)))) 
from image_type; 

2.これは個人的な好みの問題かもしれないが、スカラサブクエリを読み込み(と書き込みするのは困難になる傾向があり、スカラサブクエリし

を使用しないでください:私のポイントを説明するために、最も内側のスカラーサブクエリの結合条件に明らかなエラーがありました。

select row_to_json(row(it.name, iiv.name)) 
from image_type it 
join (select image_type_id, json_agg(name, iv_name) as name 
     from image_instance ii 
     join (select image_instance_id, json_agg(name) as iv_name 
      from image_version group by 1) iv on iv.image_instance_id = ii.id 
     group by 1) iiv using (image_type_id); 

3.モジュール化the beginning of the documentation, in the Tutorial sectionで右そこ

(強く推奨読み、あなたがいると思うが堪能):

明示的ではなく、結合と集計との定期的なサブクエリを使用します

ビューのリベラルな使用は、良いSQLデータベース デザインの重要な側面です。

create view iv_json as 
    select image_instance_id, json_agg(name) as iv_name 
    from image_version 
    group by 1; 

create view ii_json as 
    select image_type_id, json_agg(name, iv_name) as name 
    from image_instance 
    join iv_json on image_instance_id = image_instance.id 
    group by 1; 

あなたのメイン・クエリは現在次のようになります。

select row_to_json(row(it.name, ii.name)) 
from image_type it 
join ii_json ii using (image_type_id); 

のように...

これは、はるかに明らかに、テストをコーディングし、維持するのが最も簡単です。パフォーマンスはここでは問題になりません。クエリオプティマイザは、リンクされたすべてのビューを単一の実行計画にフラット化します。

最後の注意:あなたはPG9.4の+を使用している場合は、よりわかりやすい出力用json_build_object()の代わりrow_to_json()を使用することができます。

+0

@パトリックの答えをありがとう、これは非常に包括的で、私にJSONビューの使い方を教えてくれました。私はあなたの輪郭を描いた方法でこれをやろうとしましたが、ネストされているのではなく、各列にグループ分けされています。集計を含むフィールドとして各結合をネストする方法を説明できますか? –

+0

テーブルの構造や出力フォーマットを見ずに、問題の内容を説明するのは難しいですが、 'ii_json'ビューを変更して' json_agg(json_build_object( 'instance'、name、 'versions'、iv_name) 'の代わりに' json_agg(name、iv_name) 'の代わりに'同様に、各行にはイメージタイプとインスタンスの配列を持つJSONオブジェクトがあり、それぞれは名前とバージョンの配列で構成されています。それはあなたの後のことですか? – Patrick

関連する問題