Rotaie: selezionare valori univoci da una colonna


238

Ho già una soluzione funzionante, ma vorrei davvero sapere perché questo non funziona:

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

Seleziona, ma non stampa valori univoci, stampa tutti i valori, inclusi i duplicati. Ed è nella documentazione: http://guides.rubyonrails.org/active_record_querying.html#selecting-specific-fields


Risposte:


449
Model.select(:rating)

Il risultato è una raccolta di Modeloggetti. Valutazioni non semplici. E dal uniqpunto di vista, sono completamente diversi. Puoi usare questo:

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

o questo (il più efficiente)

Model.uniq.pluck(:rating)

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

Aggiornare

Apparentemente, a partire da rails 5.0.0.1, funziona solo su query di "livello superiore", come sopra. Non funziona sui proxy di raccolta (relazioni "has_many", ad esempio).

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

In questo caso, deduplicare dopo la query

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

Ho fatto un: gruppo (: valutazione) .collect {| r | r.rating} Dato che map == si raccoglie, dove posso leggere su questa sintassi che hai usato (&: rating)? Non lo vedo nella documentazione di Ruby.
alexandrecosta,

@ user1261084: vedi Simbolo # to_proc per capire .map (&: rating). Spiega PragDave
dbenhur l'

63
Vale la pena notare che Model.uniq.pluck(:rating)è il modo più efficiente per farlo - questo genera SQL che utilizza SELECT DISTINCTanziché applicare .uniqa un array
Mikey

23
In Rails 5, Model.uniq.pluck(:rating)saràModel.distinct.pluck(:rating)
neurodinamico il

2
Se vuoi selezionare valori univoci dalla relazione has_many puoi sempre fareModel.related_records.group(:some_column).pluck(:some_column)
Krzysztof Karski

92

Se hai intenzione di usare Model.select, allora potresti anche usare DISTINCT, poiché restituirà solo i valori univoci. Questo è meglio perché significa che restituisce meno righe e dovrebbe essere leggermente più veloce rispetto alla restituzione di un numero di righe e quindi dire a Rails di scegliere i valori univoci.

Model.select('DISTINCT rating')

Naturalmente, questo viene fornito se il database comprende la DISTINCTparola chiave e la maggior parte dovrebbe.


6
Model.select("DISTINCT rating").map(&:rating)per ottenere una serie di soli voti.
Kris

Ottimo per chi ha app legacy che usano Rails 2.3
Mikey il

3
Sì..questo funziona alla grande, ma restituisce solo l'attributo DISTINCT. Come è possibile restituire l'intero oggetto Modello purché sia ​​distinto? In questo modo avrai accesso a tutti gli attributi nel modello nelle istanze in cui l'attributo è unico.
zero_cool

@Jackson_Sandland Se si desidera un oggetto Model, è necessario creare un'istanza da un record nella tabella. Ma non stai selezionando un record solo un valore univoco (da quelli che possono essere più record).
Benissimo,

69

Anche questo funziona.

Model.pluck("DISTINCT rating")

Credo che spennare sia Ruby 1.9.xe versioni successive. Chiunque utilizzi una versione precedente non lo avrà. Se sei in 1.9x e versioni successive, i documenti ruby ​​dicono che funziona anche: Model.uniq.pluck (: rating)
kakubei

6
pluckè un puro metodo Rails> 3.2 che non ha dipendenze da Ruby 1.9.x Vedi apidock.com/rails/v3.2.1/ActiveRecord/Calculations/pluck
Daniel Rikowski

34

Se vuoi selezionare anche campi extra:

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"

Ciò presenta i vantaggi di non utilizzare stringhe sql e di non creare modelli di istanza


3
Questo genera un errore con Rails 5.1 / AR 5.1 => metodo indefinito `uniq '
Graham Slick

24
Model.select(:rating).uniq

Questo codice funziona come 'DISTINCT' (non come Array # uniq) poiché rotaie 3.2


5
Model.select(:rating).distinct

2
Questa è l'unica risposta ufficialmente corretta che è anche super efficiente. Tuttavia, l'aggiunta .pluck(:rating)alla fine renderà esattamente ciò che l'OP ha richiesto.
Sheharyar,

5

Se sto andando a modo giusto allora:

Query corrente

Model.select(:rating)

sta restituendo un array di oggetti e hai scritto una query

Model.select(:rating).uniq

uniq viene applicato sull'array di oggetti e ogni oggetto ha un ID univoco. uniq sta eseguendo il suo lavoro correttamente perché ogni oggetto nell'array è uniq.

Esistono molti modi per selezionare una valutazione distinta:

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

o

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

o

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

o

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

Un'altra cosa, prima e seconda query: trovare dati distinti tramite query SQL.

Queste query saranno considerate "londra" e "londra" allo stesso modo che trascureranno lo spazio, ecco perché selezionerà "londra" una volta nel risultato della query.

Terza e quarta query:

trova i dati tramite query SQL e per dati distinti applicati ruby ​​uniq mehtod. queste query saranno considerate "londra" e "londra" diverse, ecco perché selezionerà "londra" e "londra" nel risultato della query.

preferisci l'immagine allegata per una maggiore comprensione e dai un'occhiata a "Tour / In attesa di RFP".

inserisci qui la descrizione dell'immagine


6
mape collectsono alias per lo stesso metodo, non è necessario fornire esempi per entrambi.
Adam Lassek,

4

Alcune risposte non tengono conto dell'OP che desidera una serie di valori

Altre risposte non funzionano bene se il tuo modello ha migliaia di record

Detto questo, penso che una buona risposta sia:

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

Perché, in primo luogo si genera una matrice di modello (con dimensioni ridotte a causa della selezione), quindi si estrae l'unico attributo che hanno i modelli selezionati (classificazioni)


3

Se qualcuno sta cercando lo stesso con Mongoid, cioè

Model.distinct(:rating)

questo non funziona ora, ora restituisce multipli.
EUPHORAY,

non ritorna distinto
dowi,

2

Un altro modo per raccogliere colonne uniq con sql:

Model.group(:rating).pluck(:rating)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.