Szyny: wybierz unikalne wartości z kolumny

238

Mam już działające rozwiązanie, ale naprawdę chciałbym wiedzieć, dlaczego to nie działa:

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

Wybiera, ale nie drukuje unikalnych wartości, drukuje wszystkie wartości, w tym duplikaty. I to jest w dokumentacji: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields

alexandrecosta
źródło
2
Kolejny przykład z uniq stackoverflow.com/questions/8369812/...
manish nautiyal 11.02.13

Odpowiedzi:

449
Model.select(:rating)

Wynikiem tego jest zbiór Modelobiektów. Nie zwykłe oceny. I z uniqpunktu widzenia są one zupełnie inne. Możesz użyć tego:

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

lub ten (najbardziej wydajny)

Model.uniq.pluck(:rating)

# rails 5+
Model.distinct.pluck(:rating)

Aktualizacja

Najwyraźniej od wersji 5.0.0.1 działa tylko na zapytania „najwyższego poziomu”, jak wyżej. Nie działa na serwerach proxy kolekcji (na przykład relacje „has_many”).

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

W takim przypadku deduplikuj po zapytaniu

user.addresses.pluck(:city).uniq # => ['Moscow']
Sergio Tulentsev
źródło
Zrobiłem: group (: rating) .collect {| r | r.rating} Od map == zbierz, gdzie mogę przeczytać o tym sintaxie, którego użyłeś (&: ocena)? Nie widzę tego w dokumentacji Ruby.
alexandrecosta
@ user1261084: patrz Symbol # to_proc, aby zrozumieć .map (&: rating). PragDave wyjaśnia
dbenhur,
63
Warto zauważyć, że Model.uniq.pluck(:rating)jest to najbardziej efektywny sposób na zrobienie tego - generuje to SQL, który używa SELECT DISTINCTzamiast stosować się .uniqdo tablicy
Mikey
23
W Railsach 5 Model.uniq.pluck(:rating)będzieModel.distinct.pluck(:rating)
neurodynamiczny
2
Jeśli chcesz wybrać unikalne wartości z relacji has_many, zawsze możesz to zrobićModel.related_records.group(:some_column).pluck(:some_column)
Krzysztof Karski
92

Jeśli zamierzasz użyć Model.select, równie dobrze możesz po prostu użyć DISTINCT, ponieważ zwróci tylko unikalne wartości. Jest to lepsze, ponieważ oznacza, że ​​zwraca mniej wierszy i powinno być nieco szybsze niż zwracanie pewnej liczby wierszy, a następnie nakazanie Railsom wybrania unikalnych wartości.

Model.select('DISTINCT rating')

Oczywiście pod warunkiem, że baza danych rozpoznaje DISTINCTsłowo kluczowe, a większość powinna.

kakubei
źródło
6
Model.select("DISTINCT rating").map(&:rating)aby uzyskać tablicę samych ocen.
Kris,
Idealne dla osób posiadających starsze aplikacje korzystające z Rails 2.3
Mikey
3
Tak .. działa to fantastycznie - jednak zwraca tylko atrybut DISTINCT. Jak możesz zwrócić cały obiekt Model, dopóki jest on odrębny? Abyś miał dostęp do wszystkich atrybutów w modelu w przypadkach, w których atrybut jest unikalny.
zero_cool
@Jackson_Sandland Jeśli chcesz obiekt Model, musiałby zostać utworzony instancja z rekordu w tabeli. Ale nie wybierasz rekordu tylko unikalnej wartości (z wielu rekordów).
Benissimo,
69

To też działa.

Model.pluck("DISTINCT rating")
Nat
źródło
Uważam, że pluck to Ruby 1.9.x i nowsze. Każdy, kto użyje poprzedniej wersji, nie będzie go miał. Jeśli jesteś w wersji 1.9x i wyższej, ruby ​​docs mówią, że to również działa: Model.uniq.pluck (: ocena)
kakubei
6
pluckjest czystą metodą Rails> 3.2, która nie jest zależna od Ruby 1.9.x Patrz apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck
Daniel Rikowski
34

Jeśli chcesz również wybrać dodatkowe pola:

Model.select('DISTINCT ON (models.ratings) models.ratings, models.id').map { |m| [m.id, m.ratings] }
Marcin Nowicki
źródło
1
select extra fields<3 <3
cappie013
27
Model.uniq.pluck(:rating)

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

Ma to tę zaletę, że nie używa ciągów SQL i nie tworzy modeli

Cameron Martin
źródło
3
To powoduje błąd w przypadku Rails 5.1 / AR 5.1 => niezdefiniowana metoda `uniq '
Graham Slick
24
Model.select(:rating).uniq

Ten kod działa jako „DISTINCT” (nie jako Array # uniq) od szyn 3.2

kuboon
źródło
5
Model.select(:rating).distinct
hassan_i
źródło
2
To jedyna oficjalnie poprawna odpowiedź, która również jest super wydajna. Chociaż dodanie .pluck(:rating)na końcu sprawi, że będzie to dokładnie to, o co poprosił PO.
Sheharyar,
5

Jeśli idę od razu, to:

Bieżące zapytanie

Model.select(:rating)

zwraca tablicę obiektów i napisałeś zapytanie

Model.select(:rating).uniq

uniq jest stosowany na tablicy obiektów, a każdy obiekt ma unikalny identyfikator. uniq poprawnie wykonuje swoje zadanie, ponieważ każdy obiekt w tablicy jest uniq.

Istnieje wiele sposobów na wybranie odrębnej oceny:

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

lub

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

lub

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

lub

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

Jeszcze jedno, pierwsze i drugie zapytanie: znajdź różne dane według zapytania SQL.

Zapytania te będą traktowane jako „londyn”, a „londyn” to samo oznacza, że ​​zaniedbają spację, dlatego wybiorą „londyn” jeden raz w wyniku zapytania.

Trzecie i czwarte zapytanie:

znajdź dane według zapytania SQL i dla różnych danych zastosuj ruby ​​uniq mehtod. zapytania te uznają „londyn” i „londyn” za różne, dlatego w wynikach wyszukiwania wybiorą „londyn” i „londyn”.

prosimy o dołączenie obrazka dla lepszego zrozumienia i obejrzenie „Toured / Oczekuje na zapytanie ofertowe”.

wprowadź opis zdjęcia tutaj

uma
źródło
6
map& collectsą aliasami dla tej samej metody, nie ma potrzeby podawania przykładów dla obu.
Adam Lassek
4

Niektóre odpowiedzi nie biorą pod uwagę, że OP chce tablicy wartości

Inne odpowiedzi nie działają dobrze, jeśli Twój model ma tysiące rekordów

To powiedziawszy, myślę, że dobrą odpowiedzią jest:

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

Ponieważ najpierw wygenerujesz tablicę Modelu (ze zmniejszonym rozmiarem ze względu na wybór), a następnie wyodrębnisz jedyny atrybut, który mają te wybrane modele (oceny)

Fernando Fabreti
źródło
3

To znaczy, jeśli ktoś szuka tego samego w Mongoid

Model.distinct(:rating)
Vassilis
źródło
ten nie działa teraz, teraz zwraca wielokrotności.
EUPHORAY,
nie zwraca wyraźne
dowi
2

Innym sposobem na zebranie kolumn uniq z sql:

Model.group(:rating).pluck(:rating)
Slava Zharkov
źródło