gpt4 book ai didi

ruby-on-rails - 使用 Ruby on Rails 的 Postgres 公用表表达式查询

转载 作者:行者123 更新时间:2023-11-29 12:05:06 24 4
gpt4 key购买 nike

我正在尝试找到在 Rails 应用程序中使用公用表表达式执行 Postgres 查询的最佳方法,显然 ActiveRecord 不支持 CTE。

我有一个名为 user_activity_transitions 的表,其中包含一系列正在启动和停止的用户事件的记录(每行表示状态的变化:例如启动或停止)。

一个 user_activity_id 可能有很多 couples started-stopped,它们在 2 个不同的行中。如果事件当前正在进行并且尚未停止,则也可能只有“开始”。 sort_key 从第一个状态的 0 开始,每次状态更改时递增 10。

id      to_state     sort_key     user_activity_id    created_at
1 started 0 18 2014-11-15 16:56:00
2 stopped 10 18 2014-11-15 16:57:00
3 started 20 18 2014-11-15 16:58:00
4 stopped 30 18 2014-11-15 16:59:00
5 started 40 18 2014-11-15 17:00:00

我想要的是以下输出,将几个开始-停止的组合在一起,以便能够计算持续时间等。

user_activity_id     started_created_at      stopped_created_at
18 2014-11-15 16:56:00 2014-11-15 16:57:00
18 2014-11-15 16:58:00 2014-11-15 16:59:00
18 2014-11-15 17:00:00 null

表的实现方式使得运行该查询变得更加困难,但对于 future 的变化(例如新的中间状态)更加灵活,因此不会被修改。

我的 Postgres 查询(以及 Rails 中的相关代码):

query = <<-SQL
with started as (
select
id,
sort_key,
user_activity_id,
created_at as started_created_at
from
user_activity_transitions
where
sort_key % 4 = 0
), stopped as (
select
id,
sort_key-10 as sort_key2,
user_activity_id,
created_at as stopped_created_at
from
user_activity_transitions
where
sort_key % 4 = 2
)
select
started.user_activity_id AS user_activity_id,
started.started_created_at AS started_created_at,
stopped.stopped_created_at AS stopped_created_at
FROM
started
left join stopped on stopped.sort_key2 = started.sort_key
and stopped.user_activity_id = started.user_activity_id
SQL

results = ActiveRecord::Base.connection.execute(query)

它的作用是根据对排序键的模数检查“欺骗”SQL 连接 2 个连续的行。

查询工作正常。但是使用这个原始的 AR 调用让我很烦,特别是因为 connection.execute 返回的内容非常困惑。我基本上需要遍历结果并将其放入正确的哈希中。

2个问题:

  1. 有没有办法摆脱 CTE 并使用Rails 魔法?
  2. 如果没有,是否有更好的方法在美观的散列中获得我想要的结果?

请记住,我是 Rails 的新手,不是查询专家,因此可能会有明显的改进......

非常感谢!

最佳答案

虽然 Rails 不直接支持 CTE,但您可以模拟单个 CTE 并仍然利用 ActiveRecord。使用 from 子查询代替 CTE。

Thing
.from(
# Using a subquery in place of a single CTE
Thing
.select(
'*',
%{row_number() over(
partition by
this, that
order by
created_at desc
) as rank
}
)
:things
)
.where(rank: 1)

这不完全相同,但等同于...

with ranked_things as (
select
*,
row_number() over(
partition by
this, that
order by
created_at desc
) as rank
)
select *
from ranked_things
where rank = 1

关于ruby-on-rails - 使用 Ruby on Rails 的 Postgres 公用表表达式查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27491908/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com