我正在制作一种活动日历app。用户主页上显示了两种类型的事件:
这是事件表:id, user_id, content, occurs_at, created_at
目前,我正在显示按创建日期排序的这些事件,以便首先显示新添加的内容。
我想要的是首先显示所有附近的事件并按计划日期排序,然后显示正常事件并按创建日期排序。我认为它可以带来更好的用户体验,但我不知道如何去做。
更新
结束这个查询,这是几个答案的组合。
ORDER BY COALESCE(occurs_at > :min_time AND occurs_at < :max_time, 0) DESC, occurs_at ASC, created_at DESC
答案 0 :(得分:2)
order by
子句可以包含任意逻辑,而不仅仅是字段名称,因此,在伪代码中,您可以拥有
SELECT ...
...
ORDER BY (date_diff(occurs_at, now) <= '3 days'), occurs_at DESC, created_at DESC
第一个子句强制将接下来3天内发生的所有事件发送到列表顶部。然后第二个子句按降序排序,然后其他所有内容按created_at日期排序。
答案 1 :(得分:2)
正如@MarcB所提到的,你可以通过表达式进行排序,但对于PostgreSQL,表达式看起来有些不同;
SELECT * FROM Events
ORDER BY CASE WHEN (occurs_at - '3 days'::interval) < CURRENT_TIMESTAMP
THEN occurs_at
ELSE '9999-01-01'::timestamp
END, created_at;
注意,'9999-01-01'在某种程度上是一个任意选择的日期,如果有人知道“maxdate”的PostgreSQL常量,我会感兴趣:)
答案 2 :(得分:2)
更容易解释/理解。
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
计算的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计算每一行的值,使得无法使用普通索引。此recent closely related answer中有更多信息。
更短,更快一点。
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 强>
答案 3 :(得分:1)
我会通过一个字段来扩展你的SELECT子句,确定它是否附近&#34; (及时,不是地方)
SELECT
id, user_id, content, occurs_at, created_at,
case when date_diff(d,occurs_at, now) <= 3 then 1 else 0 end as isNearby
...
但我不确定您的语法,这适用于MS SQL Server