Active Record Query中基于时间的优先级

我有一个包含作业列表的表,显示时通常按created_at字段降序排序。 我正在添加一个“特色”布尔标志,这将增加客户能够更好地了解他们的工作列表的能力。 如果作业少于X天,我希望将精选列表固定在搜索结果的顶部。 如何通过现有查询修改以支持此function?

Jobs.where("expiration_date >= ? and published = ?", Date.today, true).order("created_at DESC") 

当前查询将拉回由created_at排序的所有当前已发布作业。

与其他一些数据库(如Oracle)不同,PostgreSQL具有完全function的boolean类型。 您可以直接ORDER BY子句中使用它而不应用CASE语句 – 这些对于更复杂的情况非常有用。

boolean值的排序顺序是:

 FALSE -> TRUE -> NULL 

如果ORDER BY bool_expression DESC ,则将订单反转为:

 NULL -> TRUE -> FALSE 

如果首先需要TRUE而最后是NULLS LAST ,请使用ORDER BYNULLS LAST子句 :

 ORDER BY (featured AND created_at > now() - interval '11 days') DESC NULLS LAST , created_at DESC 

当然,如果NULLS LASTcreated_at 可以NULL ,则NULLS LAST仅相关。 如果列定义为NOT NULL ,则不要打扰。

此外, FALSE将在NULL之前排序。 如果您不想区分这两者,则可以返回CASE语句,也可以输入NULLIF()COALESCE()

 ORDER BY NULLIF(featured AND created_at > now() - interval '11 days'), FALSE) DESC NULLS LAST , created_at DESC 

性能

请注意,我如何使用:

 created_at > now() - interval '11 days' 

不是

 now() - created_at < interval '11 days' 

在第一个示例中,右侧的表达式是一次计算的常量。 然后可以使用索引来查找匹配的行。 效率很高。

后者通常不能与索引一起使用。 必须为每一行计算一个值,然后才能根据右边的常量表达式检查它。 如果可以避免,请不要这样做。 永远!

不知道你想在这里实现什么。

我想你会对结果进行分页。 如果是这样,并且您希望始终在顶部显示特色作业,而不管页面如何,则应分别从DB中提取它们。 如果您只想在第一页上显示它们,请按以下方式published

 Jobs.where("expiration_date >= ?", Date.today).order("published DESC, created_at DESC") 

如果你想分开拉它们:

 @featured_jobs = Jobs.where("expiration_date >= ? and published = ?", Date.today, true).order("created_at DESC") @regular_jobs = Jobs.where("expiration_date >= ? AND published = ?", Date.today, false).order("created_at DESC") #Paginate them too ... depends on the gem you're using