Postgresqlで、順序付けられたデータのセットをプルし、それを個別のフィールドでフィルタリングするクエリを作成しようとしています。また、同じテーブル行から他のいくつかのフィールドをプルする必要がありますが、それらは個別の評価から除外する必要があります。例:
SELECT DISTINCT(user_id) user_id,
created_at
FROM creations
ORDER BY created_at
LIMIT 20
user_id
をDISTINCT
にする必要がありますが、created_atの日付が一意であるかどうかは関係ありません。 created_at日付が評価に含まれているため、結果セットに重複したuser_id
が含まれています。
また、データは日付順に並べる必要があるため、ここではDISTINCT ON
を使用することはできません。 DISTINCT ON
フィールドがORDER BY
句の最初のフィールドである必要があり、それは私が求める結果を提供しません。
DISTINCT
句を適切に使用し、そのスコープを1つのフィールドのみに制限し、他のフィールドを選択するにはどうすればよいですか?
ご存知のとおり、標準SQLはDISTINCT
を、1列または数列だけでなく、選択リスト全体に適用するものとして扱います。これは、DISTINCT
から除外する列にどの値を入れるかがあいまいであるためです。同じ理由で、標準SQLでは、_GROUP BY
_を使用したクエリにあいまいな列を含めることはできません。
しかし、PostgreSQLにはSQLの非標準の拡張機能があり、要求されていることを可能にします:DISTINCT ON (expr)
。
_SELECT DISTINCT ON (user_id) user_id, created_at
FROM creations
ORDER BY user_id, created_at
LIMIT 20
_
ORDER BY句の左端の部分として、個別の式を含める必要があります。
詳細については、 DISTINCT句 のマニュアルを参照してください。
各ユーザーの最新のcreated_atが必要な場合は、次のように集計することをお勧めします。
SELECT user_id, MAX(created_at)
FROM creations
WHERE ....
GROUP BY user_id
ORDER BY created_at DESC
これにより、各user_idの最新のcreated_atが返されます。上位20のみが必要な場合は、追加します。
LIMIT 20
編集:これは基本的にUnreasonが上で言ったのと同じことです...どの行からデータが必要かを集計によって定義します。
GROUP BY
は、グループ化された列の個別の値を保証する必要があります。これにより、目的の結果が得られる場合があります。
(私はPostgreSQLではなく、MySQLとOracleに精通していませんが、2セントを投入していることに注意してください)
MySqlで
SELECT user_id, created_at
FROM creations
GROUP BY user_id
ORDER BY user_id
Oraclesqlplusの場合
SELECT user_id, FIRST(created_at)
FROM creations
GROUP BY user_id
ORDER BY user_id
これらにより、user_id
に続いて、そのcreated_at
に関連付けられたfirstuser_id
が表示されます。別のcreated_at
が必要な場合は、FIRSTをAVG
、MIN
、MAX
、またはLAST
などの他の関数に置き換えるオプションがあります。 Oracleの場合、他の列(返されない列を含む)にORDER BY
を追加して、別のcreated_at
を取得することもできます。
サブクエリの使用は、irc#postgresqlチャネルの誰かによって提案されました。出来た:
SELECT user_id
FROM (SELECT DISTINCT ON (user_id) * FROM creations) ss
ORDER BY created_at DESC
LIMIT 20;