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つです。