Active Record-如何在第二张表上执行嵌套选择? [英] Active Record - How to perform a nested select on a second table?

查看:142
本文介绍了Active Record-如何在第二张表上执行嵌套选择?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要列出所有客户及其最新订单日期(加上分页).

I need to list all customers along with their latest order date (plus pagination).

如何使用Active Record编写以下SQL查询?

How can I write the following SQL query using Active Record?

select *,
  (
    select max(created_at)
    from orders
    where orders.customer_id = customers.id
  ) as latest_order_date
from customers
limit 25 offset 0

我尝试过此操作,但它抱怨missing FROM-clause entry for table "customers":

I tried this but it complains missing FROM-clause entry for table "customers":

Customer
  .select('*')
  .select(
    Order
      .where('customer_id = customers.id')
      .maximum(:created_at)
  ).page(params[:page])

# Generates this (clearly only the Order query):
SELECT MAX("orders"."created_at") 
FROM "orders" 
WHERE (customer_id = customers.id)

编辑:最好保留AR的参数设置和 kaminari 的分页优势.

EDIT: it would be good to keep AR's parameterization and kaminari's pagination goodness.

推荐答案

您尚未向我们提供有关这两个表之间关系的任何信息,因此我将假设Customer has_many Orders.

You haven't given us any information about the relationship between these two tables, so I will assume Customer has_many Orders.

虽然ActiveRecord不支持您要执行的操作,但它是基于 Arel ,确实如此.

While ActiveRecord doesn't support what you are trying to do, it is built on top of Arel, which does.

每个Rails模型都有一个名为arel_table的方法,该方法将返回其对应的Arel::Table.您可能希望帮助程序库使它更干净,因为默认方式有点麻烦.我将使用普通的Arel语法来最大化兼容性.

Every Rails model has a method named arel_table that will return its corresponding Arel::Table. You might want a helper library to make this cleaner because the default way is a little cumbersome. I will use the plain Arel syntax to maximize compatibility.

ActiveRecord可以理解Arel对象,并且可以接受其自身语法.

ActiveRecord understands Arel objects and can accept them alongside its own syntax.

orders = Order.arel_table
customers = Customer.arel_table

Customer.joins(:orders).group(:id).select([
  customers[Arel.star],
  orders[:created_at].maximum.as('latest_order_date')
])

哪个生产

SELECT "customers".*, MAX("orders"."created_at") AS "latest_order_date"
FROM "customers"
INNER JOIN "orders" ON "orders"."customer_id" = "customers"."id"
GROUP BY "customers"."id"

这是惯常的做法,但是,如果您仍然希望将其作为子查询,则可以这样做

This is the customary way of doing this, but if you still want to do it as a subquery, you can do this

Customer.select([
  customers[Arel.star],
  orders.project(orders[:created_at].maximum)
        .where(orders[:customer_id].eq(customers[:id]))
        .as('latest_order_date')
])

哪个给了我们

SELECT "customers".*, (
  SELECT MAX("orders"."created_at")
  FROM "orders"
  WHERE "orders"."customer_id" = "customers"."id" ) "latest_order_date"
FROM "customers"

这篇关于Active Record-如何在第二张表上执行嵌套选择?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆