【问题标题】:Is there a way to create an arel_table from a query?有没有办法从查询中创建 arel_table ?
【发布时间】:2023-01-20 03:46:29
【问题描述】:

我有两个表(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 表,即如果 A 有列 id、title、c1、c2、c3...我希望能够做到:

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

并且只在 at_f 中获取 id 和 title,但事实并非如此,我还获取了 c1、c2、c3....

我知道我能做到

at_f=A.arel_table.project(:id,:title)

但这会输出一个 Arel::SelectManager,我需要传递一个 Arel::Table(这是我无法控制的)。

我也不想在 Arel 中构建查询,因为我需要修改作为输入给出的表 A,我可以使用 _selct!joins! 来完成。

有没有办法做到这一点?我想过使用类似的东西

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")

这是它生成的查询:

# 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

【问题讨论】:

  • 我非常乐意提供帮助(我喜欢 arel 问题)但是我对这里想要的结果有点不清楚。您尝试构建的查询是什么?您希望返回哪些对象?您还需要解释这部分“我需要传递一个 Arel::Table(这是我无法控制的)”因为你无法从中得到 Arel::Table,但如果我理解上下文,我们可以让你非常接近并且功能相当。

标签: sql ruby-on-rails ruby activerecord arel


【解决方案1】:

也许我明白你在尝试什么,虽然我不确定整个 Arel::Table 部分,但我们可以从 A 得到你的 AR 关系,如下所示:

  b_table = B.arel_table
  A.joins(
     Arel::Nodes::OuterJoin.new(b, b.create_on(
        b[:id_2].eq(A.arel_table[:id])
          .and(b[:c1].eq('x'))
          .and(b[:c2].eq('y'))
     )))
   .select(:id, :title, b[:id_2].count.as('num'))
   .group(:id,:title)

这将生成一个 ActiveRecord::Relation 对象,执行时将返回仅具有以下属性的 A 对象:idtitlenum

SQL 将是:

SELECT 
  a.id, 
  a.title,
  COUNT(b.id_2) AS num
FROM 
  a
  LEFT OUTER JOIN b ON b.id_2 = a.id
    AND b.c1 = 'x'
    AND b.c2 = 'y'
GROUP BY 
  a.id,
  a.title

这相当于你现在拥有的。

如果你真的想构建你现在拥有的查询,我们当然可以毫无问题地做到这一点,但这有点干净。

如果这不是您预期的结果,请澄清,我会相应更新。

笔记我想明确表示,您在任何时候都不能“...传递一个 Arel::Table...”它还包含查询语法,因为那不是 Arel::Table 的意思。然而,我们可以生成一个 Arel::Nodes::TableAlias 哪种类型的鸭子类型 Arel::Table 用于大多数意图和目的,并将允许查询(子查询)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-05
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 1970-01-01
    • 2015-01-26
    相关资源
    最近更新 更多