详细格式
更容易解释/理解。
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
, orFALSE
和NULL
会以不同的方式排序。
- 首先,
nearby
在 CTE 中计算order by x
。
- 接下来,按相应的日期(
occurs_at
或created_at
)排序。
occurs_
at 不能NULL
用于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