ORDER BY CASE子句的范围无法正常工作

时间:2017-08-07 19:03:50

标签: mysql ruby-on-rails named-scope

我的rails模型上有一个范围,可以帮助我对对象进行排序。如下所示:

scope :active, ->(u = nil, now = "NOW()") {
  published_and_private(u).eager_load(:images)
    .where("(listing = 1 AND complete = 0) OR " +                                        # LISTING
         "(online_only = 1 AND scheduled_end_time + INTERVAL 1 DAY >= #{now}) OR " +   # TIMED
         "(online_only = 0 AND listing = 0 AND starts_at + INTERVAL 1 DAY >= #{now})") # LIVE
    .order("complete, CASE WHEN sort_index IS NOT NULL THEN sort_index " +
         "WHEN scheduled_end_time IS NOT NULL THEN scheduled_end_time " +
         "WHEN starts_at IS NOT NULL THEN starts_at ELSE #{now} + INTERVAL 10 YEAR END")
}

以下是查询运行时返回的数据库中的数据:

select id, name, complete, sort_index, starts_at, scheduled_end_time from auctions where published = 1 ORDER BY complete, CASE WHEN sort_index IS not NULL THEN sort_index WHEN scheduled_end_time IS NOT NULL THEN scheduled_end_time WHEN starts_at IS NOT NULL THEN starts_at ELSE (NOW() + INTERVAL 10 YEAR) END;


+----+-----------------------------------+----------+------------+---------------------+---------------------+
| id | name                              | complete | sort_index | starts_at           | scheduled_end_time  |
+----+-----------------------------------+----------+------------+---------------------+---------------------+
| 21 | Listing: Mountain Cabin Estate    |        0 |          1 | NULL                | NULL                |
| 17 | Multi-Item Online Only            |        0 |          2 | 2017-08-07 06:48:00 | 2017-08-21 12:48:00 |
|  9 | Multi-item Live Auction           |        0 |       NULL | 2017-08-21 18:48:02 | NULL                |
| 19 | Many Item LIVE Auction            |        0 |       NULL | 2017-08-21 18:48:02 | NULL                |
| 10 | Single Item Online Only           |        0 |       NULL | 2017-08-07 18:48:03 | 2017-08-22 00:48:02 |
| 18 | MANY Item Timed Auction           |        0 |       NULL | 2017-08-07 18:48:03 | 2017-08-22 00:48:02 |
| 22 | LISTING: Multi-parcel Real Estate |        0 |       NULL | NULL                | NULL                |
| 20 | Bad Images                        |        0 |          3 | 2017-08-21 14:48:00 | NULL                |
|  8 | Single Item Live Auction          |        1 |       NULL | 2017-08-21 18:48:02 | NULL                |
+----+-----------------------------------+----------+------------+---------------------+---------------------+

我的问题是排序索引为3的对象不合适,对于2以上的任何数字都会发生这种情况,我完全不知道为什么会这样。我期待查询将该对象放在sort_index为2的那个对象下。

非常感谢任何帮助,指导或见解。

4 个答案:

答案 0 :(得分:1)

您可以尝试使用ISNULL,例如:

.order("complete, ISNULL(sort_index), sort_index, " +
         "ISNULL(scheduled_end_time), scheduled_end_time " +
         "ISNULL(starts_at), starts_at")

答案 1 :(得分:0)

没有办法将所有这些条件都放入CASE... WHENCASE ... WHENWHERE子句中有效地创建了一个伪列。所以你所做的与以下内容没有什么不同:

SELECT *, CASE /* your logic */ END AS sort_logic 
/* 
   Notice that the sort_logic column doesn't actually exist in the table. Instead
   MySQL calculates the value and for the duration of this query
*/
WHERE /* <stuff> */
ORDER BY sort_logic

您真正想要的是一系列列值。 @Darshan有一种方法,基本上是创建一系列布尔列并将其添加到排序中:

complete, ISNULL(sort_index) DESC, 
          /*
             Desc and ASC are important here. You want NOT NULL values to float to
             the top, but you want the columns to work in ascending order.
          */
          sort_index ASC, 
          ISNULL(scheduled_end_time) DESC, scheduled_end_time ASC, 
          ISNULL(starts_at) DESC, starts_at ASC, 

您还可以选择将列值默认为MySQL最大值。在这种情况下,'9999-12-31'代表highest possible date~0 represents the max int value

complete, 
   ISNULL(sort_index, ~0), 
   ISNULL(scheduled_end_time, '9999-12-31'), 
   ISNULL(starts_at, '9999-12-31')

在这种情况下,逻辑是&#34;按complete排序,如果sort_index不是null,则使用它进行排序,否则将结果抛出到列表的末尾sort_index不是空的...&#34;并且所有其他列都遵循相同的逻辑。

答案 2 :(得分:0)

您正在寻找的订单条款可能是:

order by complete,
         sort_index,
         Coalesce(
           scheduled_end_time,
           starts_at,
           #{now} + INTERVAL 10 YEAR
         )

但是,你要将整数与这种日期进行比较,所以我不确定它是如何起作用的 - 可能是通过隐式类型转换,这不太可能导致所需的结果

也许你的意思是:

User.findById(id, function (err, user) {
    if (err) {
        console.log(err);
    }
    if (!user) {
        console.log('no user');
    }
    if (user) {
        var food = user.food.filter(function (food) { return food.type === type; });
    }
});

答案 3 :(得分:0)

尝试使用-value技巧最后排序NULL。我和其他人一样也加入了合并,这真的清理了案例陈述。

ORDER BY 
  complete, 
  -sort_index DESC, -- Sort ascending with nulls last
  COALESCE(scheduled_end_time, starts_at, now() + INTERVAL 10 YEAR)
;

您还可以查看我的sqlfiddle