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


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

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.


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,


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] }

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


3
To powoduje błąd w przypadku Rails 5.1 / AR 5.1 => niezdefiniowana metoda `uniq '
Graham Slick


5
Model.select(:rating).distinct

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


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)


3

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

Model.distinct(:rating)

ten nie działa teraz, teraz zwraca wielokrotności.
EUPHORAY,

nie zwraca wyraźne
dowi

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.