詳細形式
説明/理解が容易。
WITH x AS (
SELECT *
, COALESCE(occurs_at <= (now() + interval '3 days'), FALSE) AS nearby
FROM events
WHERE occurs_at >= now() - interval '1 hour' -- exclude older events
OR occurs_at IS NULL
) -- CTE is not strictly necessary, just to make ORDER BY clearer
SELECT *
FROM x
ORDER BY
nearby DESC
, CASE WHEN nearby THEN occurs_at ELSE created_at END
occurs_at
質問では明示的に定義されていませんが、言及された「予定日なし」は、NULL
. したがって、、COALESCE
またはFALSE
およびNULL
を使用すると、異なる方法でソートされます。
- まず、
nearby
CTE で計算された順序で並べ替えx
ます。
- 次に、それぞれの日付 (
occurs_at
またはcreated_at
) で並べ替えます。
occurs_
NULL
atはnearby
イベントには使用できません。
- そして、そもそも
created_at
定義されていると思いNOT NULL
ます。それ以外の場合は、値をどこに置くかを決定する必要がありNULL
ます。
ここでの他の回答は、定数と比較する前に列に基づいて値を計算することを提案しています。これにより、パフォーマンスが非常に低下する可能性があります。例:
date_diff(d,occurs_at, now) <= 3 -- date_diff is also tSQL, not Postgres
回避できる場合は、これを行わないでください。これにより、Postgres はすべての行の値を計算するようになり、単純なインデックスを使用できなくなります。この最近の密接に関連した回答の詳細情報。
シンプルバージョン
短く、少し速く。
SELECT *
FROM events
WHERE occurs_at >= now() - interval '1h'
OR occurs_at IS NULL
ORDER BY
COALESCE( occurs_at <= (now()::date + 3), FALSE) DESC
, CASE WHEN occurs_at <= (now()::date + 3)
THEN occurs_at ELSE created_at END;
@Joachim の sqlfiddle を使用し、セットアップを簡素化し、欠落しているケース (スケジュールされていない、過去に発生したもの) を追加し、それに対してクエリを実行しました:
-> sqlfiddle