Rails:从列中选择唯一值

ale*_*sta 225 activerecord ruby-on-rails

我已经有了一个可行的解决方案,但我真的想知道为什么这不起作用:

ratings = Model.select(:rating).uniq
ratings.each { |r| puts r.rating }
Run Code Online (Sandbox Code Playgroud)

它选择但不打印唯一值,它会打印所有值,包括重复值.它在文档中:http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields

Ser*_*sev 434

Model.select(:rating)
Run Code Online (Sandbox Code Playgroud)

结果是一组Model对象.不是简单的评级.从uniq他们的角度来看,他们完全不同.你可以用这个:

Model.select(:rating).map(&:rating).uniq
Run Code Online (Sandbox Code Playgroud)

或者这个(效率最高)

Model.uniq.pluck(:rating)

# rails 5+
Model.distinct.pluck(:rating)
Run Code Online (Sandbox Code Playgroud)

更新

显然,从rails 5.0.0.1开始,它仅适用于"顶级"查询,如上所述.不适用于集合代理(例如"has_many"关系).

Address.distinct.pluck(:city) # => ['Moscow']
user.addresses.distinct.pluck(:city) # => ['Moscow', 'Moscow', 'Moscow']
Run Code Online (Sandbox Code Playgroud)

在这种情况下,在查询后进行重复数据删除

user.addresses.pluck(:city).uniq # => ['Moscow']
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,`Model.uniq.pluck(:rating)`是最有效的方法 - 这会生成使用`SELECT DISTINCT`而不是将`.uniq`应用于数组的SQL (63认同)
  • 在Rails 5中,`Model.uniq.pluck(:rating)`将是`Model.distinct.pluck(:rating)` (23认同)
  • 如果你想从has_many关系中选择唯一值,你总是可以做`Model.related_records.group(:some_column).pluck(:some_column)` (2认同)

kak*_*bei 90

如果您要使用Model.select,那么您也可以使用DISTINCT,因为它只返回唯一值.这样做更好,因为它意味着它返回更少的行,并且应该比返回多个行稍快,然后告诉Rails选择唯一值.

Model.select('DISTINCT rating')
Run Code Online (Sandbox Code Playgroud)

当然,这是在您的数据库理解DISTINCT关键字时提供的,而且大多数应该.

  • `Model.select("DISTINCT rating").map(&:rating)`得到一个只有收视率的数组. (5认同)
  • 是的..这很棒 - 但是,它只返回DISTINCT属性.只要它不同,你如何返回整个Model对象?这样,在属性唯一的实例中,您将可以访问模型中的所有属性. (3认同)

Nat*_*Nat 63

这也有效.

Model.pluck("DISTINCT rating")
Run Code Online (Sandbox Code Playgroud)

  • `pluck`是一个纯粹的Rails> 3.2方法,它不依赖于Ruby 1.9.x请参阅http://apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck (5认同)
  • Rails 6.1 中不允许使用非属性参数,因此对于 6.1+ 上的用户,以下应该可以解决问题:`Model.pluck(Arel.sql("DISTINCT rating"))` (4认同)

小智 28

如果您还想选择额外的字段:

Model.select('DISTINCT ON (models.ratings) models.ratings, models.id').map { |m| [m.id, m.ratings] }
Run Code Online (Sandbox Code Playgroud)


Cam*_*tin 26

Model.uniq.pluck(:rating)

# SELECT DISTINCT "models"."rating" FROM "models"
Run Code Online (Sandbox Code Playgroud)

这具有不使用sql字符串而不实例化模型的优点

  • 这会引发Rails 5.1/AR 5.1 => undefined method`uniq'的错误 (3认同)

kub*_*oon 22

Model.select(:rating).uniq
Run Code Online (Sandbox Code Playgroud)

由于rails 3.2,此代码用作'DISTINCT'(而不是Array#uniq)

  • 在 Rails 6(至少 6.0.3)中,这不会生成“DISTINCT”子句,因此它是“SELECT models. rating FROM models”,然后是 Array#uniq (2认同)

小智 9

Model.select(:rating).distinct
Run Code Online (Sandbox Code Playgroud)

  • 这是唯一一个也非常高效的官方正确答案。虽然,在最后添加 `.pluck(:rating)` 将使其完全符合 OP 的要求。 (3认同)

小智 6

使用 sql 收集 uniq 列的另一种方法:

Model.group(:rating).pluck(:rating)
Run Code Online (Sandbox Code Playgroud)


uma*_*uma 5

如果我要走正确的路,那么:

当前查询

Model.select(:rating)
Run Code Online (Sandbox Code Playgroud)

正在返回对象数组并且您已经编写了查询

Model.select(:rating).uniq
Run Code Online (Sandbox Code Playgroud)

uniq 应用于对象数组,每个对象都有唯一的 id。uniq 正在正确执行其工作,因为数组中的每个对象都是 uniq。

有很多方法可以选择不同的评分:

Model.select('distinct rating').map(&:rating)
Run Code Online (Sandbox Code Playgroud)

或者

Model.select('distinct rating').collect(&:rating)
Run Code Online (Sandbox Code Playgroud)

或者

Model.select(:rating).map(&:rating).uniq
Run Code Online (Sandbox Code Playgroud)

或者

Model.select(:name).collect(&:rating).uniq
Run Code Online (Sandbox Code Playgroud)

还有一件事,第一次和第二次查询:通过 SQL 查询找到不同的数据。

这些查询将被视为“伦敦”和“伦敦”,这意味着它会忽略空间,这就是为什么它会在您的查询结果中一次选择“伦敦”。

第三次和第四次查询:

通过 SQL 查询查找数据并应用 ruby​​ uniq mehtod 来获取不同的数据。这些查询将被视为“伦敦”和“伦敦”不同,这就是为什么它会在您的查询结果中选择“伦敦”和“伦敦”。

请更喜欢附加图片以获得更多理解,并查看“Toured / Awaiting RFP”。

在此处输入图片说明

  • `map` 和 `collect` 是同一个方法的别名,无需为两者提供示例。 (6认同)