CASE
ケースが示されているほど単純な場合は、CASE
ステートメントは次のようになります:
SELECT year
, sum(CASE WHEN animal = 'kittens' THEN price END) AS kittens
, sum(CASE WHEN animal = 'puppies' THEN price END) AS puppies
FROM (
SELECT year, animal, avg(price) AS price
FROM tab_test
GROUP BY year, animal
HAVING count(*) > 2
) t
GROUP BY year
ORDER BY year;
sum()
を使用するかどうかは関係ありません 、max()
またはmin()
外部クエリの集計関数として。この場合、これらはすべて同じ値になります。
crosstab()
カテゴリが多いほど、crosstab()
を使用すると簡単になります クエリ。これは、大きなテーブルの場合も高速である必要があります 。
追加のモジュール
CREATE EXTENSION tablefunc;
この関連する回答の詳細:
SELECT * FROM crosstab(
'SELECT year, animal, avg(price) AS price
FROM tab_test
GROUP BY animal, year
HAVING count(*) > 2
ORDER BY 1,2'
,$$VALUES ('kittens'::text), ('puppies')$$)
AS ct ("year" text, "kittens" numeric, "puppies" numeric);
サイトでは追加のモジュールが許可されていないため、これにはsqlfiddleはありません。
ベンチマーク
私の主張を検証するために、小さなテストデータベースの実際のデータに近いものを使用して簡単なベンチマークを実行しました。 PostgreSQL9.1.6。 EXPLAIN ANALYZE
でテストする 、ベスト10:
10020行のテストセットアップ:
CREATE TABLE tab_test (year int, animal text, price numeric);
-- years with lots of rows
INSERT INTO tab_test
SELECT 2000 + ((g + random() * 300))::int/1000
, CASE WHEN (g + (random() * 1.5)::int) %2 = 0 THEN 'kittens' ELSE 'puppies' END
, (random() * 200)::numeric
FROM generate_series(1,10000) g;
-- .. and some years with only few rows to include cases with count < 3
INSERT INTO tab_test
SELECT 2010 + ((g + random() * 10))::int/2
, CASE WHEN (g + (random() * 1.5)::int) %2 = 0 THEN 'kittens' ELSE 'puppies' END
, (random() * 200)::numeric
FROM generate_series(1,20) g;
結果:
@bluefeet
合計実行時間:95.401ミリ秒
@wildplasser
(異なる結果、count <= 3
の行が含まれます )
合計実行時間:64.497ミリ秒
@Andreiy
(+ ORDER BY
)
&@ Erwin1-CASE
(どちらもほぼ同じパフォーマンスです)
合計実行時間:39.105ミリ秒
@ Erwin2-crosstab()
合計実行時間:17.644ミリ秒
わずか20行で、大部分が比例する(ただし無関係な)結果。 @wildplasserのCTEだけが、より多くのオーバーヘッドと少しのスパイクを持っています。
一握り以上の行がある場合、crosstab()
@Andreiyのクエリは、私の簡略化されたバージョンとほぼ同じように実行され、外部のSELECT
の集計関数になります。 (min()
、max()
、sum()
)測定可能な違いはありません(グループごとに2行のみ)。
すべてが期待どおりで、驚くことではありません。セットアップを行って、@homeで試してください。