如何使用连接表的布尔列使Rails / ActiveRecord返回唯一对象

时间:2015-07-13 20:25:45

标签: ruby-on-rails postgresql activerecord

我有一个使用ActiveRecord和Postgresql的Rails 4应用程序,有两个表:storesopen_hoursstore有许多open_hours

存储

       Column       | 
--------------------+
 id                 | 
 name               | 

OPEN_HOURS:

    Column       |
-----------------+
 id              |
 open_time       |
 close_time      |
 store_id        |

open_timeclose_time列表示自星期日午夜(即星期一开始)以来的秒数。

我想获得商店是否开放的store对象列表,因此打开的商店将排在已关闭的商店之前。这是我在Rails中的查询:

Store.joins(:open_hours).order("#{current_time} > open_time AND #{current_time} < close_time desc")

注意current_time是自上周日午夜以来的秒数。

这给了我一个商店列表,其中当前开放的商店排在封闭商店之前。但是,我在结果中得到了很多重复。

我尝试使用distinct,uniq和group方法,但它们都不起作用:

Store.joins(:open_hours).group("stores.id").group("open_hours.open_time").group("open_hours.close_time").order("#{current_time} > open_time AND #{current_time} < close_time desc")

我已经在Stackoverflow上阅读了很多问题/答案,但大多数人都没有解决order方法问题。 This question似乎是最相关的,但MAX聚合函数不适用于布尔值。

非常感谢任何帮助!感谢。

2 个答案:

答案 0 :(得分:1)

以下是我为解决问题所做的工作:

在Rails中:

is_open = "bool_or(#{current_time} > open_time AND #{current_time} < close_time)"

Store.select("stores.*, CASE WHEN #{is_open} THEN 1 WHEN #{is_open} IS NULL THEN 2 ELSE 3 END AS open").group("stores.id").joins("LEFT JOIN open_hours ON open_hours.store_id = stores.id").uniq.order("open asc")

说明:

  • is_open变量用于缩短select语句。
  • 此处需要bool_or聚合函数来对open_hours条记录进行分组。否则,每个商店可能会有两个结果(一个打开,一个关闭),这就是为什么单独使用uniq方法不能消除重复的问题
  • 使用
  • LEFT JOIN代替INNER JOIN,因此我们可以包含没有任何open_hours个对象的商店
  • 商店可以开启(即为真),关闭(即为假)或未确定(即为零),因此{此处需要{1}}声明:如果商店已开启,则 1 2 (如果未确定), 3 (如果已关闭)
  • 排序结果CASE WHEN将首先显示打开商店,然后是未确定商店,然后是已关闭商店。< / LI>

此解决方案有效,但感觉不是很优雅。如果您有更好的解决方案,请发布您的答案。非常感谢!

答案 1 :(得分:0)

您是否尝试过uniq方法,只需将其附加到最后

Store.joins(:open_hours).order("#{current_time} > open_time AND #{current_time} < close_time desc").uniq