如何在 Arel Table 中使用 Rails 中的 distinct 方法?

How to use the distinct method in Rails with Arel Table?

我正在寻找 运行 Rails 中的以下查询(我已经使用 scuttle.io 站点将我的 SQL 转换为 rails-友好语法):

这是原始查询:

SELECT pools.name AS "Pool Name", COUNT(DISTINCT stakings.user_id) AS "Total Number of Users Per Pool" from stakings
INNER JOIN pools ON stakings.pool_id = pools.id
INNER JOIN users ON users.id = stakings.user_id
INNER JOIN countries ON countries.code = users.country
WHERE countries.kyc_flow = 1
GROUP BY (pools.name);

这里是 scuttle.io 查询:

    <%Staking.select(
    [
      Pool.arel_table[:name].as('Pool_Name'), Staking.arel_table[:user_id].count.as('Total_Number_of_Users_Per_Pool')
    ]
    ).where(Country.arel_table[:kyc_flow].eq(1)).joins(
      Staking.arel_table.join(Pool.arel_table).on(
        Staking.arel_table[:pool_id].eq(Pool.arel_table[:id])
      ).join_sources
    ).joins(
      Staking.arel_table.join(User.arel_table).on(
        User.arel_table[:id].eq(Staking.arel_table[:user_id])
      ).join_sources
    ).joins(
      Staking.arel_table.join(Country.arel_table).on(
        Country.arel_table[:code].eq(User.arel_table[:country])
      ).join_sources
    ).group(Pool.arel_table[:name]).each do |x|%>
<p><%=x.Pool_Name%><p>
<p><%=x.Total_Number_of_Users_Per_Pool%>
<%end%>

现在,您可能会注意到,sctuttle.io 不包括我需要的不同参数。我究竟如何才能在这里使用 distinct 而不会出现诸如“Arel Node 不存在方法 distinct”之类的错误?或者只是语法错误?

有没有办法使用 rails ActiveRecord 编写上述查询?我确定有,但我真的不确定如何。

回答 Arel::Nodes::Count class(Arel::Nodes::Function)接受一个布尔值来区分。

def initialize expr, distinct = false, aliaz = nil
  super(expr, aliaz)
  @distinct = distinct
end

#count 表达式是相同的快捷方式,也接受单个参数

def count distinct = false
  Nodes::Count.new [self], distinct
end

所以在您的情况下,您可以使用以下任一选项

Arel::Nodes::Count.new([Staking.arel_table[:user_id]],true,'Total_Number_of_Users_Per_Pool')
# OR
Staking.arel_table[:user_id].count(true).as('Total_Number_of_Users_Per_Pool')

建议 1: 您拥有的 Arel 似乎有点矫枉过正。鉴于自然关系,您应该能够稍微简化一下,例如

country_table = Country.arel_table
Staking
  .joins(:pools,:users)
  .joins( Arel::Nodes::InnerJoin(
            country_table, 
            country_table.create_on(country_table[:code].eq(User.arel_table[:country])))
  .select( 
     Pool.arel_table[:name],
     Staking.arel_table[:user_id].count(true).as('Total_Number_of_Users_Per_Pool')
   )
  .where(countries: {kyc_flow: 1})
  .group(Pool.arel_table[:name])

建议 2:将此查询移至您的控制器。该视图没有进行数据库调用的业务。