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

求与指定SQL等效的高性能纯Ruby ActiveRecord实现方案

纯ActiveRecord替代硬编码SQL实现特定查询

需求与现有问题

需要实现的功能:查询关联特定shop_id的购物车(按created_at倒序取第1001-2000条)的客户的不重复城市,原SQL逻辑如下:

SELECT DISTINCT customers.city 
FROM customers
INNER JOIN (
  SELECT c_id 
  FROM carts
  WHERE shop_id = #{`shop_id`}
  ORDER BY created_at DESC 
  LIMIT 1000 OFFSET 1000
) AS filtered_carts ON customers.id = filtered_carts.c_id;

当前采用的ActiveRecord写法包含硬编码SQL片段,存在模型变更(如迁移改表名、字段名)时的兼容风险:

customers = Customer
  .select(:city)
  .distinct
  .joins("
    INNER JOIN (
      SELECT c_id
      FROM carts
      WHERE shop_id = #{`shop_id`}
      ORDER BY created_at DESC
      LIMIT 1000 OFFSET 1000
    ) AS filtered_carts
    ON customers.id = filtered_carts.c_id
  ")

纯ActiveRecord实现方案

方案1:基于子查询对象拼接(直观易读)

先通过ActiveRecord构建子查询,再将其SQL片段嵌入join语句,避免硬编码表名、字段名:

# 构建购物车子查询:筛选目标shop_id的第1001-2000条记录(按created_at倒序)
filtered_carts_subquery = Cart.select(:c_id)
                              .where(shop_id: shop_id)
                              .order(created_at: :desc)
                              .limit(1000)
                              .offset(1000)

# 关联子查询获取客户不重复城市
customers = Customer.select(:city)
                    .distinct
                    .joins("INNER JOIN (#{filtered_carts_subquery.to_sql}) AS filtered_carts ON customers.id = filtered_carts.c_id")

方案2:纯Arel构建关联(无任何SQL字符串)

利用Arel完全通过Ruby方法构建关联逻辑,彻底避免硬编码:

# 构建购物车子查询的Arel对象
cart_subquery = Cart.select(:c_id)
                    .where(shop_id: shop_id)
                    .order(created_at: :desc)
                    .limit(1000)
                    .offset(1000)
                    .arel

# 通过Arel构建Inner Join并执行查询
customers = Customer.select(:city)
                    .distinct
                    .joins(
                      Customer.arel_table.join(cart_subquery, Arel::Nodes::InnerJoin)
                        .on(Customer.arel_table[:id].eq(cart_subquery[:c_id]))
                        .join_sources
                    )

方案优势

两种方案均依赖ActiveRecord模型定义动态生成SQL,后续若修改Cart模型的表名、c_id字段名,或Customer模型的主键,查询会自动适配,无需手动修改SQL片段,解决了硬编码带来的兼容问题。


内容的提问来源于stack exchange,提问作者Da V

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 09:37:43