DISTINCT ON
を使用すると、グループごとに最も長い名前の乗客を簡単に取得できます。 。
しかし、それ(または他の簡単な方法)を単一のSELECT
で元のクエリと組み合わせる方法はわかりません。 。 2つの別々のサブクエリに参加することをお勧めします:
SELECT *
FROM ( -- your original query
SELECT orig
, count(*) AS flight_cnt
, count(distinct passenger) AS pass_cnt
, percentile_cont(0.5) WITHIN GROUP (ORDER BY bags) AS bag_cnt_med
FROM table1
GROUP BY orig
) org_query
JOIN ( -- my addition
SELECT DISTINCT ON (orig) orig, passenger AS pass_max_len_name
FROM table1
ORDER BY orig, length(passenger) DESC NULLS LAST
) pas USING (orig);
USING
join句では、便利なことにorig
のインスタンスを1つだけ出力します。 、したがって、SELECT *
を使用するだけです。 外側のSELECT
。
passenger
の場合 NULLにすることもできますが、NULLS LAST
を追加することが重要です。 :
同じグループ内の同じ最大長の複数の乗客名から、任意の選択を取得します -ORDER BY
に式を追加しない限り タイブレーカーとして。上にリンクされた回答の詳細な説明。
パフォーマンス?
通常、特にシーケンシャルスキャンでは、シングルスキャンの方が優れています。
上記のクエリは2つを使用します スキャン(多分インデックス/インデックスのみのスキャン)。ただし、テーブルが大きすぎてキャッシュに収まらない場合を除いて、2回目のスキャンは比較的安価です(ほとんどの場合)。 Lukasは、シングルのみの代替クエリを提案しました SELECT
追加:
, (ARRAY_AGG (passenger ORDER BY LENGTH (passenger) DESC))[1] -- I'd add NULLS LAST
アイデアは賢いですが、array_agg
ORDER BY
を使用 あまりうまく機能しませんでした。 (グループごとのORDER BY
のオーバーヘッド かなりの量であり、配列の処理にも費用がかかります。)
同じアプローチは、カスタム集計関数 first()
を使用すると安価になる可能性があります こちらのPostgresWikiで指示されているように
。または、 Cで記述されたバージョンで、PGXNで入手可能
を使用すると、さらに高速になります。 。配列処理の余分なコストを排除しますが、それでもグループごとのORDER BY
が必要です 。 高速になる可能性があります 少数のグループのみ。次に、次を追加します:
, first(passenger ORDER BY length(passenger) DESC NULLS LAST)
ゴードン
およびfirst_value()
。ウィンドウ関数は後に適用されます 集計関数。同じSELECT
で使用するには 、passenger
を集計する必要があります どういうわけか 最初-キャッチ22。ゴードンはサブクエリでこれを解決します-標準のPostgresで優れたパフォーマンスを発揮するもう1つの候補です。
first()
サブクエリなしでも同じことを行い、より単純で少し高速になるはずです。ただし、それでも別のDISTINCT ON
よりも高速になることはありません。 ほとんどの場合、グループあたりの行数は少なくなります。グループごとに多数の行がある場合、通常、再帰CTE手法の方が高速です。関連するすべての一意のorig
を保持する別のテーブルがある場合は、さらに高速な手法があります。 値。詳細:
最善の解決策は、さまざまな要因によって異なります。プリンの証拠は食べることです。パフォーマンスを最適化するには、セットアップでテストする必要があります。上記のクエリは最速の1つです。