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

时间:2012-10-01 19:09:48

标签: sql ruby-on-rails postgresql activerecord

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

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

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

2 个答案:

答案 0 :(得分:3)

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

boolean值的排序顺序为:

FALSE -> TRUE -> NULL

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

NULL -> TRUE -> FALSE

如果您希望TRUE先行,NULL持续,请使用NULLS LAST clause of ORDER BY

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

当然,NULLS LAST仅在featuredcreated_at NULL时才有意义。如果列定义为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'

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

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

答案 1 :(得分:0)

不确定你想在这里实现什么。

我猜你会对结果进行分页。如果是这样,并且您希望始终在顶部显示特色作业,而不管页面如何,则应分别从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