私の前の質問に続いて:
PostgreSQL 9.0でcrosstab()ピボットテーブルを作成しています
crosstab()
関数を使用してageband
のピボットテーブルを作成できました。これを使用して、基本のジオメトリレステーブルのビューまたはテーブルを作成できます。
ただし、さらに分析するためにジオメトリを割り当てるためにgazetteers_and_addresses.unit_postcode
テーブルにリンクする必要があるため、これはまだあまり役に立ちません。
両方のテーブルのテーブル構造と、クロス集計の作成に使用した元のコードを添付します。
CREATE OR REPLACE VIEW adult_social_care.vw_ageband AS (
SELECT * FROM crosstab(
'SELECT postcode_nospace_, ageband, count(ageband) as total_count
FROM adult_social_care.activities_in_localities_asc
GROUP BY postcode_nospace_, ageband
ORDER BY postcode_nospace_'
,$$VALUES ('18-24'::text), ('25-34'), ('35-44'), ('45-54'), ('55-64'), ('65-74'), ('75-84'), ('85-94'), ('95 AND OVER')$$)
AS ct("postcode" text, "18-24" numeric, "25-34" numeric,"35-44" numeric, "45-54" numeric, "55-64" numeric, "65-74" numeric, "75-84" numeric, "85-94" numeric, "95 AND OVER" numeric));
テーブルの定義:
activities_in_localities_asc
:
CREATE TABLE adult_social_care.activities_in_localities_asc (
ogc_fid integer NOT NULL,
sort numeric(5,0),
ageband character(12),
postcode_nospace_ character(8),
wkb_geometry geometry,
CONSTRAINT activities_in_localities_asc_pkey PRIMARY KEY (ogc_fid)
);
unit_postcode
:
CREATE TABLE gazetteers_and_addresses.unit_postcode (
oogc_fid serial NOT NULL,
pc_area character(10),
postcode_nospaces text,
wkb_geometry geometry
);
可能であれば、最後に、すべてのフィールドの合計を示す別のフィールドを割り当てて、total_count
を指定します。
これが可能であれば、1つのジオメトリレステーブルとunit_postcode
を使用して、さまざまな要素に動的ビューを作成できます。
まず、表の定義にchar(n)
が含まれていると、提示されたクエリは機能しません- 前の質問で説明したように 。最初に text
またはvarchar
に変換する必要があります。
これは現在のテーブル定義で機能します:
_SELECT * FROM crosstab(
'SELECT postcode_nospace_::text, ageband::text, count(ageband) AS ct
FROM adult_social_care.activities_in_localities_asc
GROUP BY 1, 2
ORDER BY 1'
,$$VALUES ('18-24'::text), ('25-34'), ('35-44'), ('45-54'), ('55-64')
, ('65-74'), ('75-84'), ('85-94'), ('95 AND OVER')$$
)
AS t("postcode" text
, "18-24" bigint, "25-34" bigint,"35-44" bigint, "45-54" bigint, "55-64" bigint
, "65-74" bigint, "75-84" bigint, "85-94" bigint, "95 AND OVER" bigint);
_
また、bigint
ではなくnumeric
を使用して、別の不要な型変換を保存しています(count()
はbigint
を返します)。
詳細な説明:
ただし、@ dezsoが提案するように、テーブルのデータ型をALTER
にtext
するほうがよいまたは、長さの制限を維持したい場合は、CHECK
制約を追加するか、varchar(n)
を使用します。 char(n)
は使用しないでください。
_ALTER TABLE activities_in_localities_asc
ALTER COLUMN ageband TYPE varchar(12)
, ALTER COLUMN postcode_nospace_ TYPE varchar(8);
ALTER TABLE gazetteers_and_addresses.unit_postcode
ALTER COLUMN pc_area TYPE varchar(10);
_
そうすれば、元の列の値をキャストする必要がなくなります。
_SELECT * FROM crosstab(
'SELECT postcode_nospace_, ageband, count(ageband)
...
_
ただし、理想的には、ageband
は enum
または(私の好み)ルックアップテーブルを参照するIDであり、単純でエラーが発生しやすいtext
...キーワード:正規化。
テーブル上に構築しますが、text
またはvarchar()
列を使用します。
元のクエリを [〜#〜] cte [〜#〜] にラップし、UNION
クエリで結果を2回呼び出します。2回目の呼び出しでは、郵便番号ごとの合計が追加されます。
_SELECT * FROM crosstab(
$$WITH cte AS (
SELECT postcode_nospace_, ageband, count(ageband) AS ct
FROM adult_social_care.activities_in_localities_asc
GROUP BY 1, 2
)
TABLE cte -- original results
UNION ALL -- add total per postcode
SELECT postcode_nospace_, 'total' AS ageband, sum(ct) AS ct
FROM cte
GROUP BY 1
ORDER BY 1$$ -- dollar-quotes to include single quotes easily
,$$VALUES ('18-24'::text), ('25-34'), ('35-44'), ('45-54'), ('55-64')
, ('65-74'), ('75-84'), ('85-94'), ('95 AND OVER'), ('total')$$
)
AS t("postcode" text
, "18-24" bigint, "25-34" bigint,"35-44" bigint, "45-54" bigint, "55-64" bigint
, "65-74" bigint, "75-84" bigint, "85-94" bigint, "95 AND OVER" bigint, "total" bigint);
_
TABLE
コマンドについて:
関連するCTEの例: