从自联接表获得最短持续时间

时间:2017-06-22 09:56:28

标签: sql ruby-on-rails activerecord orm

在构建查询时需要一些帮助。我在@Rule MainActivityTestRule表和bookings表之间存在一对多的关系。每次预订状态更改时,都会生成一个新的booking_versions行,其中指定了booking_versionsstatus列。我定位以获得状态状态更改之间的最短持续时间。这就是我现在尝试过的事情

created_at

它的rails代码仍然使用纯sql。此查询无法正常工作。也许你可以建议如何在最短时间内进行预订()。

巴士预订版本架构(item_id是预订的外键)

def self.min( filter )
  query = <<-SQL
    SELECT bv1.item_id AS 'obj_id', MIN(
    bv2.created_at - bv1.created_at) AS 'mintime'
    FROM bus_booking_versions AS bv1
    INNER JOIN bus_booking_versions AS bv2
    ON bv1.item_id = bv2.item_id
    WHERE bv1.status = ?
    AND bv1.created_at >= ?
    AND bv1.created_at <= ?
    AND bv2.status IN (?)
    AND bv2.created_at >= ?
    AND bv2.created_at <= ?
  SQL
  self.find_by_sql([query, filter.start_status, filter.from_start, filter.to_start, filter.end_statuses, filter.from_end, filter.to_end])
end

版本由纸尾宝石以这种方式创建

  create_table "bus_booking_versions", force: :cascade do |t|
    t.string   "item_type",  limit: 255,        null: false
    t.integer  "item_id",    limit: 4,          null: false
    t.string   "event",      limit: 255,        null: false
    t.string   "whodunnit",  limit: 255
    t.text     "object",     limit: 4294967295
    t.datetime "created_at"
    t.integer  "status",     limit: 4
  end

1 个答案:

答案 0 :(得分:1)

由于我不知道您正在使用哪个数据库引擎,因此我会写出一般的SQL语句。您选择的数据库引擎可能有更好的方法。

您可以使用子查询来获取&#34; next&#34;而不是将同一个表连接在一起(您只需比较相同的行,由于您的bv1.item_id = bv2.item_id)。在表中排。然后,您只需遍历表的一个实例。

具体来说,像这样的子查询,找到最晚的created_at,它比当前行的created_at(即&#34;下一行&#34;)更晚,是你想要的比较:

select min(created_at) from bus_booking_versions bv2 where bv1.item_id=bv2.item_id and created_at > bv1.created_at

这是一般查询。我已经使用了mysql的timediff函数,但您可以将其更改为您的特定数据库引擎计算日期时间差异的方法。根据您的数据库引擎,可能还有更好的方法来执行此操作。

select
    bv1.item_id as 'obj_id',
    mintime = timediff
        ( 
            (
                select 
                    min(created_at) 
                from 
                    bus_booking_versions bv2 
                where 
                    bv1.item_id=bv2.item_id
                    and created_at > bv1.created_at
            ),
            bv1.created_at
        )
from
    #tmp1 bv1
where
    timediff((select min(created_at) from bus_booking_versions bv2 where bv1.item_id=bv2.item_id and created_at > bv1.created_at), bv1.created_at) > 0
    and timediff((select min(created_at) from bus_booking_versions bv2 where bv1.item_id=bv2.item_id and created_at > bv1.created_at), bv1.created_at) is not null
order by
    timediff

希望它看起来很简单。我已经在选择中扩展了timediff /子查询,以便更清楚地了解正在发生的事情。 where子句中的timediff()与select中的完全相同,只是它们被压缩为一行。这是为了清除两个bus_booking_versions具有相同created_at的实例,或者比较时间戳是最终/唯一行(没有后续行)的实例。

您可以在where子句的其余部分添加以检查其他参数;我刚刚将它们排除在外以保持查询清晰易懂。如果您只想返回第一行,可以将.first方法链接到ruby中的语句。