Schienen: Wählen Sie eindeutige Werte aus einer Spalte aus


238

Ich habe bereits eine funktionierende Lösung, würde aber gerne wissen, warum dies nicht funktioniert:

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

Es werden eindeutige Werte ausgewählt, aber nicht gedruckt. Es werden alle Werte einschließlich der Duplikate gedruckt. Und es ist in der Dokumentation: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields


2
Ein weiteres Beispiel mit uniq stackoverflow.com/questions/8369812/…
manish nautiyal

Antworten:


449
Model.select(:rating)

Das Ergebnis ist eine Sammlung von ModelObjekten. Keine einfachen Bewertungen. Und aus uniqSicht sind sie völlig anders. Sie können dies verwenden:

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

oder dies (am effizientesten)

Model.uniq.pluck(:rating)

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

Aktualisieren

Ab Rails 5.0.0.1 funktioniert es anscheinend nur bei Abfragen der obersten Ebene, wie oben. Funktioniert nicht mit Sammlungsproxys (z. B. "has_many" -Relationen).

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

In diesem Fall nach der Abfrage deduplizieren

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

Ich habe eine: group (: Bewertung) .collect {| r | r.rating} Seit map == collect, wo kann ich über diese von Ihnen verwendete Sintax lesen (&: Bewertung)? Ich sehe das nicht in Rubys Dokumentation.
Alexandrecosta

@ user1261084: Siehe Symbol # to_proc , um .map (&: Bewertung) zu verstehen. PragDave erklärt
Dbenhur

63
Es ist erwähnenswert, dass dies Model.uniq.pluck(:rating)der effizienteste Weg ist - dies generiert SQL, das verwendet SELECT DISTINCTund nicht .uniqauf ein Array
angewendet wird

23
In Rails 5 Model.uniq.pluck(:rating)wirdModel.distinct.pluck(:rating)
neurodynamisch

2
Wenn Sie eindeutige Werte aus der Beziehung has_many auswählen möchten, können Sie dies jederzeit tunModel.related_records.group(:some_column).pluck(:some_column)
Krzysztof Karski

92

Wenn Sie verwenden möchten Model.select, können Sie auch einfach verwenden DISTINCT, da nur die eindeutigen Werte zurückgegeben werden. Dies ist besser, da dies bedeutet, dass weniger Zeilen zurückgegeben werden und etwas schneller sein sollte als die Rückgabe mehrerer Zeilen und die Anweisung von Rails, die eindeutigen Werte auszuwählen.

Model.select('DISTINCT rating')

Dies setzt natürlich DISTINCTvoraus, dass Ihre Datenbank das Schlüsselwort versteht und die meisten sollten.


6
Model.select("DISTINCT rating").map(&:rating)um eine Reihe nur der Bewertungen zu erhalten.
Kris

Ideal für diejenigen mit Legacy-Apps, die Rails 2.3 verwenden
Mikey

3
Ja, das funktioniert fantastisch - aber es gibt nur das DISTINCT-Attribut zurück. Wie können Sie das gesamte Modellobjekt zurückgeben, solange es eindeutig ist? Damit Sie in Fällen, in denen das Attribut eindeutig ist, Zugriff auf alle Attribute im Modell haben.
zero_cool

@Jackson_Sandland Wenn Sie ein Modellobjekt möchten, muss dieses aus einem Datensatz in der Tabelle instanziiert werden. Sie wählen jedoch nicht nur einen eindeutigen Wert für einen Datensatz aus (möglicherweise mehrere Datensätze).
Benissimo

69

Das funktioniert auch.

Model.pluck("DISTINCT rating")

Ich glaube, Zupfen ist Ruby 1.9.x und höher. Jeder, der eine frühere Version verwendet, wird sie nicht haben. Wenn Sie in 1.9x und höher sind, sagen die Ruby-Dokumente, dass dies auch funktioniert: Model.uniq.pluck (: Bewertung)
Kakubei

6
pluckist eine reine Rails> 3.2-Methode, die keine Abhängigkeit von Ruby 1.9.x hat. Siehe apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck
Daniel Rikowski

34

Wenn Sie auch zusätzliche Felder auswählen möchten:

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"

Dies hat den Vorteil, dass keine SQL-Zeichenfolgen verwendet und keine Modelle instanziiert werden


3
Dies wirft einen Fehler mit Rails 5.1 / AR 5.1 => undefinierte Methode `uniq '
Graham Slick

24
Model.select(:rating).uniq

Dieser Code funktioniert als 'DISTINCT' (nicht als Array # uniq), da Rails 3.2


5
Model.select(:rating).distinct

2
Dies ist die einzige offiziell korrekte Antwort, die auch sehr effizient ist. Durch Hinzufügen .pluck(:rating)am Ende wird jedoch genau das erreicht, was das OP verlangt hat.
Sheharyar

5

Wenn ich auf dem richtigen Weg bin, dann:

Aktuelle Abfrage

Model.select(:rating)

gibt ein Array von Objekten zurück und Sie haben eine Abfrage geschrieben

Model.select(:rating).uniq

uniq wird auf ein Array von Objekten angewendet und jedes Objekt hat eine eindeutige ID. uniq führt seine Aufgabe korrekt aus, da jedes Objekt im Array uniq ist.

Es gibt viele Möglichkeiten, eine bestimmte Bewertung auszuwählen:

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

oder

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

oder

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

oder

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

Eine weitere Sache, erste und zweite Abfrage: Finden Sie unterschiedliche Daten durch SQL-Abfrage.

Diese Abfragen werden als "London" und "London" betrachtet. Dies bedeutet, dass der Platz vernachlässigt wird. Aus diesem Grund wird in Ihrem Abfrageergebnis einmal "London" ausgewählt.

Dritte und vierte Abfrage:

Finden Sie Daten durch SQL-Abfrage und für bestimmte Daten angewendet Ruby Uniq Mehtod. Diese Abfragen werden als "London" und "London" unterschiedlich betrachtet. Aus diesem Grund werden in Ihrem Abfrageergebnis "London" und "London" ausgewählt.

Bitte ziehen Sie zum besseren Verständnis das angehängte Bild vor und sehen Sie sich "Toured / Awaiting RFP" an.

Geben Sie hier die Bildbeschreibung ein


6
map& collectSind Aliase für dieselbe Methode, müssen keine Beispiele für beide angegeben werden.
Adam Lassek

4

Einige Antworten berücksichtigen nicht, dass das OP eine Reihe von Werten wünscht

Andere Antworten funktionieren nicht gut, wenn Ihr Modell Tausende von Datensätzen enthält

Trotzdem denke ich, dass eine gute Antwort lautet:

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

Da Sie zuerst ein Array von Modellen generieren (mit einer aufgrund der Auswahl verringerten Größe), extrahieren Sie dann das einzige Attribut, das diese ausgewählten Modelle haben (Bewertungen).


3

Wenn jemand mit Mongoid dasselbe sucht, dann ist das so

Model.distinct(:rating)

Dieser funktioniert jetzt nicht, er gibt jetzt Vielfache zurück.
EUPHORAY

kehrt nicht eindeutig zurück
dowi

2

Eine andere Möglichkeit, Uniq-Spalten mit SQL zu sammeln:

Model.group(:rating).pluck(:rating)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.