sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQL 9.3:動的ピボットテーブル

    これはcrosstab()で行うことができます 追加のモジュールtablefuncから:

    SELECT b
         , COALESCE(a1, 0) AS "A1"
         , COALESCE(a2, 0) AS "A2"
         , COALESCE(a3, 0) AS "A3"
         , ... -- all the way up to "A30"
    FROM   crosstab(
             'SELECT colb, cola, 1 AS val FROM matrix
              ORDER  BY 1,2'
            , $$SELECT 'A'::text || g FROM generate_series(1,30) g$$
           ) AS t (b text
                 , a1  int, a2  int, a3  int, a4  int, a5  int, a6  int
                 , a7  int, a8  int, a9  int, a10 int, a11 int, a12 int
                 , a13 int, a14 int, a15 int, a16 int, a17 int, a18 int
                 , a19 int, a20 int, a21 int, a22 int, a23 int, a24 int
                 , a25 int, a26 int, a27 int, a28 int, a29 int, a30 int);
    

    NULLの場合 0の代わりに 動作します。SELECT *にすることもできます。 外側のクエリで。
    詳細な説明:

    • PostgreSQLクロス集計クエリ

    ここでの特別な「難しさ」:実際の「価値」はありません。したがって、1 AS valを追加します 最後の列として。

    不明な数のカテゴリ

    完全に動的なクエリ(結果タイプが不明)は、単一のクエリでは不可能です。 2つが必要です クエリ。最初に上記のようなステートメントを動的に作成してから実行します。詳細:

    • 単一のSQLステートメントを使用して複数のmax()値を選択する

    • PostgreSQLは列を行に変換しますか?転置しますか?

    • PostgreSQLでクロス集計用の列を動的に生成する

    • CASEおよびGROUPBYを使用したピボットの動的な代替手段

    カテゴリが多すぎます

    列の最大数(1600)を超えると、結果を個々の列で表すことができないため、従来のクロス集計は不可能になります。 (また、人間の目は、これほど多くの列を持つテーブルを読み取ることはほとんどできません)

    hstoreのような配列またはドキュメントタイプ またはjsonb 代替手段です。配列を使用したソリューションは次のとおりです。

    SELECT colb, array_agg(cola) AS colas
    FROM  (
       SELECT colb, right(colb, -1)::int AS sortb
            , CASE WHEN m.cola IS NULL THEN 0 ELSE 1 END AS cola
       FROM        (SELECT DISTINCT colb FROM matrix) b
       CROSS  JOIN (SELECT DISTINCT cola FROM matrix) a
       LEFT   JOIN matrix m USING (colb, cola)
       ORDER  BY sortb, right(cola, -1)::int 
       ) sub
    GROUP  BY 1, sortb
    ORDER  BY sortb;
    
    • 次のコマンドで値の完全なグリッドを作成します:

                  (SELECT DISTINCT colb FROM matrix) b
      CROSS  JOIN (SELECT DISTINCT cola FROM matrix) a
      
    • LEFT JOIN 既存の組み合わせ、名前の数値部分で並べ替え、配列に集約します。

      • right(colb, -1)::int 'A3'から主役をトリミングし、数字を整数にキャストして、適切なソート順を取得します。

    基本マトリックス

    0のテーブルが必要な場合 1 ここで、x = y 、これはもっと安くすることができます:

    SELECT x, array_agg((x = y)::int) AS y_arr
    FROM   generate_series(1,10) x
         , generate_series(1,10) y
    GROUP  BY 1
    ORDER  BY 1;
    

    SQLフィドル コメントで提供したものに基づいて構築します。

    sqlfiddle.comには現在、配列値の表示を強制終了するバグがあることに注意してください。だから私はtextにキャストしました それを回避するためにそこにあります。




    1. Terraformを使用したMySQL/MariaDBVaultデータベースシークレットエンジンのプロビジョニング

    2. Oracleインスタンスのシャットダウンと起動

    3. 外部キーでリンクされたテーブルにデータを挿入する

    4. 統計の自動更新を表示する別の方法