You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Active Record查询结果创建Arel::Table?

问题

我有A、B两张数据表,已经基于两表关联创建了一个复杂的Active::Record::Relation对象,通过ActiveRecord::Base.connection.exec_query joined.to_sql能正确执行查询,返回需要的A.id、A.title、b.num字段。

我想把这个关联查询的结果作为Arel::Table传入后续程序,但执行at_j=joined.arel_table时,生成的Arel表是基于原数据表A的,包含A的全部字段而非仅选中的字段,而且不包含B表的字段。

我尝试从筛选后的表创建Arel表:

filtered=A.select(:id,:title)
at_f=filtered.arel_table

但at_f还是包含A表的c1、c2、c3等全部字段,不是仅id和title。

我知道可以用at_f=A.arel_table.project(:id,:title)实现,但这个方法返回的是Arel::SelectManager,而我需要的是Arel::Table。

另外,我不想直接用Arel构建查询,因为需要通过_select!和joins!修改传入的A表对象。我试过at_f=Arel::Table.new(filtered.to_sql)但失败了,有没有可行的方案?

附生成关联查询对象的代码:

A._select!(:id,:title,'b.num')
bf=B.where(c1: 'x',c2: 'y')
num=bf.select('id_2 AS A_id, COUNT(id_2) AS num').group(:id_2)
A.joins!("LEFT OUTER JOIN (#{num.to_sql}) b ON A.id = b.A_id")

生成的SQL语句:

# A.to_sql:
SELECT `A`.`id`, `A`.`title`, `b`.`num` 
  FROM `A` LEFT OUTER JOIN 
    (SELECT id_2 AS A_id, COUNT(id_2) AS num 
      FROM `B` WHERE `B`.`c1` = 'x' AND `B`.`c2` = 'y' 
      GROUP BY `B`.`id_2`) b 
    ON A.id = b.A_id

解决方案

方法1:将查询结果包装为临时Arel表

Arel::Table本质映射物理表或视图,无法直接从ActiveRecord::Relation生成,但可以把现有查询结果当作临时表来创建Arel对象:

# 获取已构建好的查询SQL
query_sql = A.to_sql

# 创建命名临时表的Arel对象
joined_table = Arel::Table.new('joined_result')

# 后续使用时,将临时表嵌套进新查询的FROM子句
new_query = Arel::SelectManager.new(joined_table)
new_query.project(joined_table[:id], joined_table[:title], joined_table[:num])
         .where(joined_table[:num].gt(0))

# 最终生成的SQL会自动嵌套原查询:
# SELECT joined_result.id, joined_result.title, joined_result.num FROM (你的原查询SQL) joined_result WHERE joined_result.num > 0

方法2:手动定义Arel表的字段集合

如果不需要嵌套查询,只是需要一个仅包含指定字段的Arel::Table对象,可以手动覆盖默认字段:

# 基于原A表创建Arel对象
custom_arel_table = A.arel_table
# 手动设置可用字段,只保留需要的id、title和关联的num
custom_arel_table.columns = [:id, :title, :num].map { |col| Arel::Attribute.new(custom_arel_table, col) }

# 后续使用时,仅能访问指定字段
custom_arel_table[:num] # 正常访问
custom_arel_table[:c1]  # 报错,字段已被移除

方法3:用数据库视图持久化查询结构

如果该关联查询会被多次使用,可先创建数据库视图,再基于视图生成Arel表:

-- 创建视图
CREATE VIEW joined_A_B AS
SELECT `A`.`id`, `A`.`title`, `b`.`num` 
FROM `A` LEFT OUTER JOIN 
  (SELECT id_2 AS A_id, COUNT(id_2) AS num 
   FROM `B` WHERE `B`.`c1` = 'x' AND `B`.`c2` = 'y' 
   GROUP BY `B`.`id_2`) b 
ON A.id = b.A_id;

在Rails中创建对应模型(仅关联视图):

class JoinedAB < ApplicationRecord
  self.table_name = 'joined_A_B'
end

# 直接获取符合需求的Arel表
joined_arel_table = JoinedAB.arel_table

内容的提问来源于stack exchange,提问作者Francisco Herrerias-Azcue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:25:19