在Ruby on Rails中正确执行查询的方式

3

我刚开始学习Ruby on Rails,有一个关于稍微复杂一些查询的问题。到目前为止,我在查看Rails指南时做了一些简单的查询,并且效果非常好。

现在,我正在尝试从数据库中获取一些ID,并使用这些ID获取实际对象并对它们进行操作。获取这些ID比简单的Object.find方法要复杂一些。

以下是我的查询语句:

select * from quotas q, requests r
where q.id=r.quota_id
and q.status=3
and r.text is not null
and q.id in
(
select A.id from (
select max(id) as id, name 
from quotas
group by name) A
)
order by q.created_at desc
limit 1000;

当我从sql管理器执行此查询时,这将为我提供1000个id。我想首先获取id列表,然后按id查找对象。

有没有一种方法可以直接使用此查询获取这些对象?避免查找ids?我通过谷歌搜索发现您可以执行以下查询:

ActiveRecord::Base.connection.execute(query);
2个回答

3
假设Quota has_many:requests
Quota.includes(:requests).
  where(status:3).
  where('requests.text is not null').
  where("quotas.id in (#{subquery_string_here})").
  order('quotas.created_at desc').limit(1000)

我虽然不是专家,但大部分基本的 SQL 功能都被嵌入了 ActiveRecord。你还可以考虑使用 group 和 pluck 方法来消除丑陋的字符串子查询。
在关系对象上调用 to_sql 方法会显示与其等效的 SQL 命令,并可能有助于您的调试。

非常感谢您的回复。我遇到了一个错误,错误信息为“表 'quotas' 缺少 FROM 子句条目”。我在哪里缺少了 FROM 子句?您能告诉我吗? - Gandalf StormCrow

0
我会为此使用find_by_sql。我不能保证这完全正确,但据我回忆,您几乎可以将SQL语句放入find_by_sql中,并将结果列作为调用它的类的对象数组的属性返回:
  status = 3
  Quota.find_by_sql('
    select * 
    from quotas q, requests r
    where q.id=r.quota_id
    and q.status= ?
    and r.text is not null
    and q.id in
    (
      select A.id from (
      select max(id) as id, name 
      from quotas
      group by name) A
    )
    order by q.created_at desc
    limit 1000;', status)

如果你以前习惯于编写原始 SQL,那么使用这种语法可能比串联一堆 ActiveRecord 方法更好 - 结果是相同的,所以只是看你觉得哪个更易读。

顺便说一下,在 SQL 查询中不应使用字符串插值(即 #{variable} 语法)。相反,应该使用 '?' 语法(参见我的示例)以避免 SQL 注入风险。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接