如何使用 arel/关系代数获取不同的值

Posted

技术标签:

【中文标题】如何使用 arel/关系代数获取不同的值【英文标题】:How to fetch distinct values with arel/relational algebra 【发布时间】:2011-03-09 08:30:26 【问题描述】:

我正在尽我最大的努力围绕 arel 及其背后的关系代数弯曲我的大脑,但是如何表示 SELECT DISTINCT 一直是我无法理解的。谁能解释一下如何做:

SELECT DISTINCT title FROM posts; 

非常感谢!

【问题讨论】:

我不知道 arel,但是根据我对 C.J.Date 的“Database in Depth”的阅读,在关系代数中,查询的结果是一组元组。因此,如果 arel 遵循这一理论,则默认值应该是 distinct。 【参考方案1】:

Post.select('DISTINCT title')

更新 1:

在发帖时,这在 Arel 中不可用。现在,ActiveRecord::QueryMethods 有 uniq 方法 (http://apidock.com/rails/ActiveRecord/QueryMethods/uniq),所以你想要:

Post.select(:title).uniq

更新 2: 看起来 Arel 现在支持这种行为。 @maerics 有正确的答案。如果它不是被接受的答案,我会删除它。

【讨论】:

不完全是代数,但很难与它的效率争论;-) 这种方法有一个致命的问题:如果您有多个范围和一个 select 语句,将它们链接在一起会导致 SQL 无效。 这不是 AREL,因此无法回答问题。【参考方案2】:

前面的答案是 Rails 方式,不是吗?不是阿雷尔的方式。

这适用于arel 1.x:

posts = Table(:posts)
posts.project(Arel::Distinct.new(posts[:title]))

我猜还有另一种“更正确”的方法可以通过 API 做到这一点,但我还没有弄清楚。

【讨论】:

这是真的。此答案适用于 Arel 1.x,将不再有效。 你知道有什么替代方案吗?【参考方案3】:

Arel 的做法是:

t = Arel::Table.new(:foo)
count_distinct = t[:field].count(true)
count_distinct.to_sql # => "COUNT(DISTINCT `foo`.`field`)"

【讨论】:

这并没有严格回答这个问题,但它确实回答了 my 问题:你如何使用 Arel 表达count(DISTINCT attr)【参考方案4】:

由于 AREL 在其操作中始终使用 SET,重复的行结果将被自动删除。只需使用普通的 Project (Phi) 操作即可。

【讨论】:

这在理论上是个好主意,但在现实中显然是错误的。 Arel 查询将从任何投影返回重复条目,除非明确受到“distinct”方法的约束。【参考方案5】:

使用纯 Arel(不是 Rails/ActiveRecord)有一个“不同”的方法:

Arel::VERSION # => '3.0.2'
posts = Arel::Table.new(:posts)
posts.project(posts[:title])
posts.distinct
posts.to_sql # => 'SELECT DISTINCT "posts"."title" FROM "posts"'

奇怪的是,根据其他 Arel 方法,“distinct”方法是不可链接的。

【讨论】:

对于 Arel 版本,5.0.1,这不再有效 :(. Arel 6,一切正常。它也是可链接的,因为它返回 SelectManager。 arel 6.0.3 这节省了我的时间,虽然我使用了distinct_on【参考方案6】:

如果您使用范围执行此操作:

  scope :recent, lambda |count|
    select("DISTINCT posts.*").
    joins(:whatever).
    limit(count).
    order("posts.updated_at DESC")
  

【讨论】:

以上是关于如何使用 arel/关系代数获取不同的值的主要内容,如果未能解决你的问题,请参考以下文章

函数式编程关心类型(代数结构)之间的关系

如何通过关系代数表达参照完整性约束?

关系代数

数据库的关系代数表达式

数据库系统原理之关系代数

银行场景的关系代数