从自连接表中获取最短持续时间
Posted
技术标签:
【中文标题】从自连接表中获取最短持续时间【英文标题】:get minimum duration from self join table 【发布时间】:2017-06-22 09:56:28 【问题描述】:在构建查询方面需要一些帮助。我在bookings
表和booking_versions
表之间存在一对多的关系。每次预订状态更改时,都会生成一个新的booking_versions
行,其中指定了status
和created_at
列。我的目标是获得状态状态更改之间的最短持续时间。这是我从现在开始尝试的方法
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
那是 Rails 代码,它仍然使用纯 sql。此查询无法正常工作。可能您可以建议如何获得运行最短时间()的预订。
巴士预订版本架构(item_id 是预订的外键)
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
paper tail gem 以这种方式创建版本
has_paper_trail on: [:create, :update],
class_name: "Bus::BookingVersion",
meta: status: Proc.new |t| t.status if t.status_changed?
【问题讨论】:
如果您要添加表结构和具有预期输出的两三个样本数据,这将很容易提供帮助。 提示:您可以添加数据库标签,提供预期结果示例,您将有机会从 dba 中获得答案。 【参考方案1】:由于我不知道您使用的是哪个数据库引擎,所以我将编写一个通用的 SQL 语句。您选择的数据库引擎可能有更好的方法来做到这一点。
您可以使用子查询来获取表中的“下一个”行,而不是将同一个表连接在一起(由于您的bv1.item_id = bv2.item_id
,您将只比较相同的行)。然后,您只需遍历表的一个实例。
具体来说,像这样的子查询,它会找到最早的 created_at,它晚于当前行的 created_at(即“下一行”),这是您想要比较的:
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
希望它看起来很简单。我已经扩展了选择中的时间差异/子查询,以便更清楚地了解正在发生的事情。 where 子句中的 timediff() 与 select 中的完全相同,只是它们被压缩为一行。这是为了清除两个 bus_booking_version 具有相同 created_at 的实例,或者正在比较的时间戳是最后/唯一行(没有后面的行)。
您可以添加其余的 where 子句来检查您的其他参数;我只是将它们排除在外,以保持查询清晰易懂。如果您只想返回第一行,则可以将 .first
方法链接到您的 ruby 语句。
【讨论】:
就是这样,非常感谢。专门为详细解答。这东西有效以上是关于从自连接表中获取最短持续时间的主要内容,如果未能解决你的问题,请参考以下文章
如何从自定义 UITableViewCell 获取值到 ViewController?