4

でクロス集計関数を使用しpostgresqlpivot table. ただし、クエリ内で SQL を構造化する方法を理解するのに苦労しています。私のデータは 4 つの列で構成され、次のようになります。

ここに画像の説明を入力

次のコードを使用してこのテーブルを作成します。

CREATE TABLE ct(id SERIAL, zone_id int, group_id int, area double precision);
INSERT INTO ct(zone_id, group_id, area) VALUES(1,2,6798.50754160784);
INSERT INTO ct(zone_id, group_id, area) VALUES(1,3,10197.7613124118);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,1,85708.8676744647);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,2,56006.5971338327);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,3,5584.33145616642);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,5,8611.99732832252);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,6,36103.5509183704);
INSERT INTO ct(zone_id, group_id, area) VALUES(2,8,9801.14541428806);
INSERT INTO ct(zone_id, group_id, area) VALUES(5,1,45796.0020793546);

postgresqlドキュメントに厳密に従って、クエリで次のコードを使用しますcrosstab

SELECT *
FROM crosstab(
  'select zone_id, group_id, area
   from ct
   ')
AS ct(row_name integer, 
      g_1 double precision, 
      g_2 double precision, 
      g_3 double precision, 
      g_4 double precision, 
      g_5 double precision, 
      g_6 double precision, 
      g_7 double precision, 
      g_8 double precision);

これにより、次の表が得られますが、これは私が望んでいるものではありません。

ここに画像の説明を入力

たとえば、行 2 では、次の値が必要です。

85708.8676744647, 56006.5971338327, 5584.33145616642, NULL, 8611.99732832252, 36103.5509183704, NULL, 9801.14541428806

代わりに、値は次のとおりです。

85708.8676744647, 56006.5971338327, 5584.33145616642, 8611.99732832252, 36103.5509183704, 9801.14541428806

ただし、値が無視されているように見えるため、から までnullの列名は元のグループに対応していません。g1g8

4

2 に答える 2

2

2つのパラメータcrosstab()でバリアントを使用します。

SELECT * FROM crosstab(
   'SELECT zone_id, group_id, area
    FROM   ct
    ORDER  BY 1,2'

   ,'SELECT g FROM generate_series(1,8) g'  -- ! Provide values explicitly
   )
AS ct(
     row_name integer
   , g_1 float8, g_2 float8
   , g_3 float8, g_4 float8
   , g_5 float8, g_6 float8
   , g_7 float8, g_8 float8);

これにより、どの値がどの出力列に入るのかを明示的に宣言します。したがって、関数はNULL値を入力する場所を認識しています。この場合generate_series()、1から8までの数字を8行に提供すると便利です。VALUES式は代替手段になります。

'VALUES (1), (2), (3), (4), (5), (6), (7), (8)'

ORDER BYまた、最初のパラメータクエリの句を忘れないでください。

この関連する回答で詳細な説明を提供しました。

于 2012-10-14T22:55:00.543 に答える
1

tablefunc 拡張機能を作成できないため、デモで動作させることはできませんが、9.2.1 を実行しているデスクトップでは動作します。

SELECT *
FROM crosstab(' 
    select 
        s.zone_id, s.group_id, area
    from 
        ct
        right join (
            (select distinct zone_id from ct) z(zone_id)
            cross join
            generate_series(1, 8) g(group_id)
        ) s on s.group_id = ct.group_id and s.zone_id = ct.zone_id
    order by s.zone_id, s.group_id
') AS ct (
    row_name integer, 
    g_1 double precision, 
    g_2 double precision, 
    g_3 double precision, 
    g_4 double precision, 
    g_5 double precision, 
    g_6 double precision, 
    g_7 double precision, 
    g_8 double precision
);
于 2012-10-14T21:39:56.387 に答える