2010-06-28 26 views
11

Je fais de mon mieux pour infléchir mon cerveau autour de l'arel et de l'algèbre relationnelle derrière elle, mais comment représenter un SELECT DISTINCT élude constamment ma compréhension. Quelqu'un peut-il expliquer comment arel:Comment extraire des valeurs distinctes avec l'algèbre arel/relationnelle

SELECT DISTINCT title FROM posts; 

Merci beaucoup!

+1

Je ne sais pas Arel mais de ma lecture de « Base de données en profondeur » par CJDate, en algèbre relationnelle le résultat d'une requête est un ensemble de tuples. Donc, si Arel suit cette théorie que distincte devrait être la valeur par défaut. –

Répondre

1

Post.select('DISTINCT title')

Mise à jour 1:

Au moment du poste, ce n'était pas disponible en Arel. Ces jours-ci, ActiveRecord :: QueryMethods a la méthode uniq (http://apidock.com/rails/ActiveRecord/QueryMethods/uniq), de sorte que vous voudriez:

Post.select(:title).uniq 

Mise à jour 2: Ressemble Arel prend désormais en charge ce comportement. @maerics a la bonne réponse. Je supprimerais ceci si ce n'était pas la réponse acceptée.

+0

Pas exactement algébrique, mais difficile à argumenter avec son efficacité ;-) – jemmons

+2

Il y a un problème fatal avec cette approche: si vous avez plus d'une portée avec une instruction select, les chaîner ensemble peut causer un SQL non valide. –

+5

Ce n'est pas AREL, et donc il ne répond pas à la question. –

6

La réponse précédente est la façon Rails, non? Pas la façon Arel.

Cela fonctionne pour 1.x:

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

Je suppose qu'il ya une autre façon « plus juste » de le faire via l'API, mais je n'ai pas compris cela encore.

+4

Cela ne semble pas fonctionner maintenant. –

+1

Ceci est vrai. Cette réponse était pour Arel 1.x et ne fonctionnera plus. – numbers1311407

+1

Savez-vous quelle est l'alternative? –

3

Si vous faites cela en utilisant un champ:

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

Depuis AREL utilise toujours SET dans son fonctionnement les résultats, en double ligne seront automatiquement supprimés. Utilisez simplement une opération Project (Phi) normale.

+0

C'est une bonne idée en théorie, mais c'est manifestement faux en réalité. Les requêtes Arel renvoient des entrées en double à partir de n'importe quelle projection sauf si la méthode "distinct" le contraint explicitement. – maerics

12

Utilisation Arel pur (non Rails/ActiveRecord) il existe une méthode "distinct": Méthode

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

Curieusement, le "distinct" est chainable pas, par les autres méthodes Arel.

+0

Je l'ai cherché depuis un certain temps, merci beaucoup! – Joe

+0

Avec la version Arel, '5.0.1', cela ne fonctionne plus :(. –

+1

Arel 6, tout fonctionne parfaitement, il est aussi chaînable, car il retourne SelectManager – Slotos

8

La façon Arel de le faire est la suivante:

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

' count (true) 'fonctionne très bien pour Arel 3 –