Rails:从列中选择唯一值

Posted

技术标签:

【中文标题】Rails:从列中选择唯一值【英文标题】:Rails: select unique values from a column 【发布时间】:2022-01-18 06:09:59 【问题描述】:

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

ratings = Model.select(:rating).uniq
ratings.each  |r| puts r.rating 

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

【问题讨论】:

另一个使用 uniq ***.com/questions/8369812/…的例子 【参考方案1】:
Model.select(:rating)

其结果是Model 对象的集合。不是普通的评级。而从uniq的角度来看,它们是完全不同的。你可以使用这个:

Model.select(:rating).map(&:rating).uniq

或者这个(最有效的):

Model.uniq.pluck(:rating)

导轨 5+

Model.distinct.pluck(:rating)

更新

显然,从 rails 5.0.0.1 开始,它只适用于“***”查询,就像上面一样。不适用于集合代理(例如,“has_many”关系)。

Address.distinct.pluck(:city) # => ['Moscow']
user.addresses.distinct.pluck(:city) # => ['Moscow', 'Moscow', 'Moscow']

在这种情况下,查询后去重

user.addresses.pluck(:city).uniq # => ['Moscow']

【讨论】:

我做了一个:group(:rating).collect |r| r.rating 由于 map == collect,我在哪里可以了解您使用的这个 sintax (&:rating)?我在 Ruby 的文档中没有看到这一点。 @user1261084:请参阅Symbol#to_proc 以了解 .map(&:rating)。 PragDave explains 值得注意的是,Model.uniq.pluck(:rating) 是最有效的方法——这会生成使用 SELECT DISTINCT 的 SQL,而不是将 .uniq 应用于数组 在 Rails 5 中,Model.uniq.pluck(:rating) 将是 Model.distinct.pluck(:rating) 如果您想从 has_many 关系中选择唯一值,您可以随时使用Model.related_records.group(:some_column).pluck(:some_column)【参考方案2】:

如果您打算使用Model.select,那么您不妨只使用DISTINCT,因为它只会返回唯一值。这更好,因为这意味着它返回更少的行,并且应该比返回一些行然后告诉 Rails 选择唯一值稍微快一些。

Model.select('DISTINCT rating')

当然,前提是您的数据库理解 DISTINCT 关键字,而且大多数情况下都应该这样做。

【讨论】:

Model.select("DISTINCT rating").map(&:rating) 获取仅包含评分的数组。 非常适合那些使用 Rails 2.3 的旧版应用程序 是的..这很棒 - 但是,它只返回 DISTINCT 属性。只要它不同,你怎么能返回整个模型对象?这样您就可以在属性唯一的情况下访问模型中的所有属性。 @Jackson_Sandland 如果您想要一个模型对象,则需要从表中的记录中实例化它。但您选择的记录不仅仅是一个唯一值(可能是多条记录)。【参考方案3】:

这也有效。

Model.pluck("DISTINCT rating")

【讨论】:

我相信 pluck 是 Ruby 1.9.x 及更高版本。任何使用以前版本的人都不会拥有它。如果你是 1.9x 及以上,ruby 文档说这也有效:Model.uniq.pluck(:rating) pluck 是一个纯 Rails > 3.2 方法,它不依赖于 Ruby 1.9.x 请参阅apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck Rails 6.1 中将不允许使用非属性参数,因此对于 6.1+ 的用户,以下内容应该可以解决问题:Model.pluck(Arel.sql("DISTINCT rating"))【参考方案4】:

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

Model.select('DISTINCT ON (models.ratings) models.ratings, models.id').map  |m| [m.id, m.ratings] 

【讨论】:

select extra fields 【参考方案5】:
Model.uniq.pluck(:rating)

# SELECT DISTINCT "models"."rating" FROM "models"

这样的好处是不使用sql字符串,不实例化模型

【讨论】:

这会引发 Rails 5.1 / AR 5.1 的错误 => 未定义的方法 `uniq'【参考方案6】:
Model.select(:rating).uniq

自rails 3.2以来,此代码用作“DISTINCT”(而不是Array#uniq)

【讨论】:

在 Rails 6(至少 6.0.3)中,这不会生成 DISTINCT 子句,所以它是 SELECT models.rating FROM models 然后是 Array#uniq【参考方案7】:
Model.select(:rating).distinct

【讨论】:

这是唯一一个官方正确的答案,也是超级有效的。虽然,在末尾添加 .pluck(:rating) 将使其完全符合 OP 的要求。【参考方案8】:

如果我是正确的,那么:

当前查询

Model.select(:rating)

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

Model.select(:rating).uniq

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

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

Model.select('distinct rating').map(&:rating)

Model.select('distinct rating').collect(&:rating)

Model.select(:rating).map(&:rating).uniq

Model.select(:name).collect(&:rating).uniq

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

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

第三次和第四次查询:

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

请附上图片以获得更多理解,并查看“巡回/等待 RFP”。

【讨论】:

map & collect 是同一个方法的别名,不需要分别举例。【参考方案9】:

如果有人正在寻找与 Mongoid 相同的东西,那就是

Model.distinct(:rating)

【讨论】:

这个现在不行了,它现在返回倍数。 不返回不同的【参考方案10】:

有些答案没有考虑到 OP 想要一个值数组

如果您的模型有数千条记录,则其他答案效果不佳

也就是说,我认为一个好的答案是:

    Model.uniq.select(:ratings).map(&:ratings)
    => "SELECT DISTINCT ratings FROM `models` " 

因为,首先您生成一个模型数组(由于选择而减小了大小),然后您提取了这些选定模型具有的唯一属性(评级)

【讨论】:

【参考方案11】:

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

Model.group(:rating).pluck(:rating)

【讨论】:

赞成为该问题提供原始解决方案。这甚至可能比 DISTINCT 子句更高效,具体取决于 DB。【参考方案12】:

您可以使用以下 Gem:active_record_distinct_on

Model.distinct_on(:rating)

产生以下查询:

SELECT DISTINCT ON ( "models"."rating" ) "models".* FROM "models"

【讨论】:

【参考方案13】:
Model.pluck("DISTINCT column_name")

【讨论】:

以上是关于Rails:从列中选择唯一值的主要内容,如果未能解决你的问题,请参考以下文章

Rails:如何从列中获取唯一值

火花数据集:如何从列中获取唯一值的出现次数

如何使用 Laravel 迁移从列中删除唯一约束?

MYSQL - 从列中选择一个值或(如果没有给出值)全选[关闭]

选择总和列,然后从列中获取最小值

选择小于另一列中特定值的唯一值