提问人:sunny1304 提问时间:6/17/2023 最后编辑:sunny1304 更新时间:6/19/2023 访问量:98
Rails 使用其他 2 个虚拟列计算虚拟列
Rails calculating a virtual column using 2 other virtual columns
问:
我需要帮助将以下MySQL查询转换为ActiveRecord查询,该查询将生成与IP记录作为对象的关系。 为了更好地解释这一点,如何在 ActiveRecord 查询中将两个虚拟列相和到第三列中转换以下查询?
select a_id
u_c,
i_c,
(u_c + i_c) as t_c
from (
select distinct a.id as a_id,
( SELECT count(b.id) FROM UP b
WHERE b.i_p_id = a.id
AND b.role = "L"
) as u_c,
( SELECT count(b.id) from UP b
WHERE b.institution_package_id = a.id
AND b.role = "I"
) as i_c
from IP a
left outer join UP b on b.IP = a.id
) sub
让我再解释一下。 我有 2 个表,我正在查询第一个表并计算 3 个虚拟列。 第 3 列将是其他 2 个虚拟列的总和。 感谢您的帮助。
答:
1赞
Siim Liiser
6/19/2023
#1
在 SQL 中编写复杂的查询并通过 rails 执行它们是一个简单、好的、通常是更短的解决方案。
但是,如果您真的想将 Rails 工具用于可重用性和/或安全性目的,那么这个查询可以通过 Arel 来实现,Arel 是 ActiveRecord 查询在内部构建的工具。
这被视为私有 API,可能会发生变化。升级导轨时要小心。
class IP < ActiveRecord::Base
has_many :ups, foreign_key: :IP, class_name: 'UP'
end
class UP < ActiveRecord::Base
end
a = IP.arel_table.alias('a')
b = UP.arel_table.alias('b')
first_subquery = Arel::Nodes::Grouping.new(
UP.from(b).where(
b[:i_p_id].eq(a[:id]).and(b[:role].eq('L'))
).select(b[:id].count).arel
)
second_subquery = Arel::Nodes::Grouping.new(
UP.from(b).where(
b[:institution_package_id].eq(a[:id]).and(b[:role].eq('I'))
).select(b[:id].count).arel
)
sub = IP.left_joins(:ups).distinct.select(
a[:id].as('a_id'),
first_subquery.as('u_c')
second_subquery.as('i_c')
).arel.as('sub')
Arel::SelectManager.new.from(sub).project(
sub[:a_id],
sub[:u_c],
sub[:i_c],
(sub[:u_c] + sub[:i_c]).as('t_c')
).to_sql
它会产生这样的东西
SELECT sub."a_id",
sub."u_c",
sub."i_c",
(sub."u_c" + sub."i_c") AS t_c
FROM (
SELECT DISTINCT "a"."id" AS a_id,
(
(
SELECT COUNT("b"."id")
FROM "UP" "b"
WHERE "b"."i_p_id" = "a"."id"
AND "b"."role" = 'L'
)
) AS u_c,
(
(
SELECT COUNT("b"."id")
FROM "UP" "b"
WHERE "b"."institution_package_id" = "a"."id"
AND "b"."role" = 'I'
)
) AS i_c
FROM "IP"
LEFT OUTER JOIN "UP" ON "UP"."IP" = "IP"."id"
) sub;
我添加了几个别名以使其类似于初始查询,但由于 Arel 负责引用它们,因此可以删除大多数别名。
下一个:在导轨中显示控制器的图像
评论
sql = "Select * from ... your sql query here" records_array = ActiveRecord::Base.connection.execute(sql)