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

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

    フォームの表に基づいて私の答えを作成します:

    CREATE TABLE tbl (
       sl_no int
     , username text
     , designation text
     , salary int
    );
    

    各行は、返される新しい列になります。このような動的リターンタイプでは、データベースへの1回の呼び出しでこれを完全に動的にすることはほとんど不可能です。 2つのステップによるソリューションのデモンストレーション :

    1. クエリを生成する
    2. 生成されたクエリを実行する

    一般に、これはテーブルが保持できる列の最大数によって制限されます。したがって、1600行を超える(またはそれより少ない)テーブルのオプションではありません。詳細:

    • PostgreSQL選択クエリの最大列数はいくつですか

    Postgres9.3以前

    crosstab()を使用した動的ソリューション

    • 完全に動的で、どのテーブルでも機能します。 2つでテーブル名を入力します 場所:
    SELECT 'SELECT *
    FROM   crosstab(
           ''SELECT unnest(''' || quote_literal(array_agg(attname))
                               || '''::text[]) AS col
                 , row_number() OVER ()
                 , unnest(ARRAY[' || string_agg(quote_ident(attname)
                                  || '::text', ',') || ']) AS val
            FROM   ' || attrelid::regclass || '
            ORDER  BY generate_series(1,' || count(*) || '), 2''
       ) t (col text, '
         || (SELECT string_agg('r'|| rn ||' text', ',')
             FROM (SELECT row_number() OVER () AS rn FROM tbl) t)
         || ')' AS sql
    FROM   pg_attribute
    WHERE  attrelid = 'tbl'::regclass
    AND    attnum > 0
    AND    NOT attisdropped
    GROUP  BY attrelid;

    単一のパラメータで関数にラップできます...
    次の形式のクエリを生成します:

    SELECT *
    FROM   crosstab(
           'SELECT unnest(''{sl_no,username,designation,salary}''::text[]) AS col
                 , row_number() OVER ()
                 , unnest(ARRAY[sl_no::text,username::text,designation::text,salary::text]) AS val
            FROM   tbl
            ORDER  BY generate_series(1,4), 2'
       ) t (col text, r1 text,r2 text,r3 text,r4 text)
    

    目的の結果を生成します:

    col         r1    r2      r3     r4
    -----------------------------------
    sl_no       1      2      3      4
    username    A      B      C      D
    designation XYZ    RTS    QWE    HGD
    salary      10000  50000  20000  34343
    

    unnest()を使用した単純なソリューション

    SELECT 'SELECT unnest(''{sl_no, username, designation, salary}''::text[] AS col)
         , ' || string_agg('unnest('
                        || quote_literal(ARRAY[sl_no::text, username::text, designation::text, salary::text])
                        || '::text[]) AS row' || sl_no, E'\n     , ') AS sql
    FROM   tbl;
    
    • 数列を超えるテーブルの場合は低速です。

    次の形式のクエリを生成します:

    SELECT unnest('{sl_no, username, designation, salary}'::text[]) AS col
         , unnest('{10,Joe,Music,1234}'::text[]) AS row1
         , unnest('{11,Bob,Movie,2345}'::text[]) AS row2
         , unnest('{12,Dave,Theatre,2356}'::text[]) AS row3
         , unnest('{4,D,HGD,34343}'::text[]) AS row4
    

    同じ結果。

    Postgres 9.4+

    crosstab()を使用した動的ソリューション

    可能であればこれを使用してください。残りを打ち負かします。

    SELECT 'SELECT *
    FROM   crosstab(
           $ct$SELECT u.attnum, t.rn, u.val
            FROM  (SELECT row_number() OVER () AS rn, * FROM '
                                  || attrelid::regclass || ') t
                 , unnest(ARRAY[' || string_agg(quote_ident(attname)
                                  || '::text', ',') || '])
                     WITH ORDINALITY u(val, attnum)
            ORDER  BY 1, 2$ct$
       ) t (attnum bigint, '
         || (SELECT string_agg('r'|| rn ||' text', ', ')
             FROM  (SELECT row_number() OVER () AS rn FROM tbl) t)
         || ')' AS sql
    FROM   pg_attribute
    WHERE  attrelid = 'tbl'::regclass
    AND    attnum > 0
    AND    NOT attisdropped
    GROUP  BY attrelid;

    attnumでの操作 実際の列名の代わりに。よりシンプルで高速。結果をpg_attributeに結合します もう一度、または9.3ページの例のように列名を統合します。
    次の形式のクエリを生成します:

    SELECT *
    FROM   crosstab(
           $ct$SELECT u.attnum, t.rn, u.val
            FROM  (SELECT row_number() OVER () AS rn, * FROM tbl) t
                 , unnest(ARRAY[sl_no::text,username::text,designation::text,salary::text])
                    WITH ORDINALITY u(val, attnum)
            ORDER  BY 1, 2$ct$
       ) t (attnum bigint, r1 text, r2 text, r3 text, r4 text);
    

    これは、高度な機能の全範囲を使用します。説明するには多すぎます。

    unnest()を使用した単純なソリューション

    1つのunnest() 複数のアレイを並行してアンネストできるようになりました。

    SELECT 'SELECT * FROM unnest(
      ''{sl_no, username, designation, salary}''::text[]
    , ' || string_agg(quote_literal(ARRAY[sl_no::text, username::text, designation::text, salary::text])
                  || '::text[]', E'\n, ')
        || E') \n AS t(col,' || string_agg('row' || sl_no, ',') || ')' AS sql
    FROM   tbl;
    

    結果:

    SELECT * FROM unnest(
     '{sl_no, username, designation, salary}'::text[]
    ,'{10,Joe,Music,1234}'::text[]
    ,'{11,Bob,Movie,2345}'::text[]
    ,'{12,Dave,Theatre,2356}'::text[])
     AS t(col,row1,row2,row3,row4)
    

    SQLフィドル 9.3ページで実行されています。



    1. MySQLのデータベースクエリ効率の最大化-パート1-

    2. プレビュー:AzureDataStudio用のSentryOneプランエクスプローラー拡張機能

    3. JPA SQL Server JDBCタイプの方言マッピングなし:-9

    4. Oracleで数値を含まない行を返す2つの方法