Sto cercando di trovare tutti gli utenti con un ID maggiore di 200, ma ho qualche problema con la sintassi specifica.
User.where(:id > 200)
e
User.where("? > 200", :id)
hanno fallito entrambi.
Eventuali suggerimenti?
Sto cercando di trovare tutti gli utenti con un ID maggiore di 200, ma ho qualche problema con la sintassi specifica.
User.where(:id > 200)
e
User.where("? > 200", :id)
hanno fallito entrambi.
Eventuali suggerimenti?
Risposte:
Prova questo
User.where("id > ?", 200)
?
, piuttosto che sottolineare 200
?
L'ho testato solo in Rails 4 ma esiste un modo interessante di utilizzare un intervallo con un where
hash per ottenere questo comportamento.
User.where(id: 201..Float::INFINITY)
genererà l'SQL
SELECT `users`.* FROM `users` WHERE (`users`.`id` >= 201)
Lo stesso può essere fatto per meno che con -Float::INFINITY
.
Ho appena pubblicato una domanda simile chiedendo di farlo con le date qui su SO .
>=
vs >
Per evitare che le persone debbano scavare e seguire i commenti, ecco i punti salienti.
Il metodo sopra genera solo una >=
query e non a >
. Esistono molti modi per gestire questa alternativa.
Per numeri discreti
È possibile utilizzare una number_you_want + 1
strategia come sopra in cui sono interessato agli utenti id > 200
ma in realtà cerco id >= 201
. Questo va bene per numeri interi e numeri in cui è possibile incrementare di una singola unità di interesse.
Se il numero viene estratto in una costante ben denominata, questa può essere la più facile da leggere e comprendere a colpo d'occhio.
Logica invertita
Possiamo usare il fatto che x > y == !(x <= y)
e usare la catena dove non.
User.where.not(id: -Float::INFINITY..200)
che genera l'SQL
SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))
Questo richiede un secondo in più per leggere e ragionare, ma funzionerà per valori o colonne non discreti in cui non è possibile utilizzare + 1
strategia.
Tavolo Arel
Se vuoi divertirti, puoi usare il Arel::Table
.
User.where(User.arel_table[:id].gt(200))
genererà l'SQL
"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"
Le specifiche sono le seguenti:
User.arel_table #=> an Arel::Table instance for the User model / users table
User.arel_table[:id] #=> an Arel::Attributes::Attribute for the id column
User.arel_table[:id].gt(200) #=> an Arel::Nodes::GreaterThan which can be passed to `where`
Questo approccio ti darà l' esatto SQL a cui sei interessato, tuttavia non molte persone usano direttamente la tabella Arel e possono trovarla confusa e / o confusa. Tu e il tuo team saprete cosa è meglio per voi.
A partire da Rails 5 puoi farlo anche con le date!
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
genererà l'SQL
SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')
Una volta rilasciato Ruby 2.6 (25 dicembre 2018) sarai in grado di utilizzare la nuova sintassi della gamma infinita! Invece di 201..Float::INFINITY
poter scrivere 201..
. Maggiori informazioni in questo post del blog .
where
abbinamenti di base . Perché >
suggerisco di usare a >= (number_you_want + 1)
per semplicità. Se vuoi davvero assicurarti che sia solo una >
query puoi accedere alla tabella ARel. Ogni classe che eredita ActiveRecord
ha un arel_table
metodo getter che restituisce il valore Arel::Table
per quella classe. Le colonne sulla tabella sono accessibili con il []
metodo like User.arel_table[:id]
. Questo restituisce un Arel::Attributes::Attribute
che puoi chiamare gt
e trasmettere 200
. Questo può essere quindi passato a where
. es User.where(User.arel_table[:id].gt(200))
.
User.where(created_at: 3.days.ago..DateTime::Infinity.new)
.
WHERE (users.created_at >= '2016-04-09 14:31:15' AND users.created_at < #<Date::Infinity:0x00>)
(segni di spunta intorno ai nomi di tabelle e colonne omessi per la formattazione dei commenti SO).
Se vuoi una scrittura più intuitiva, esiste una gemma chiamata squeel che ti permetterà di scrivere le tue istruzioni in questo modo:
User.where{id > 200}
Nota i caratteri "parentesi graffe" {} ed id
è solo un testo.
Tutto quello che devi fare è aggiungere il tergipavimento al tuo Gemfile:
gem "squeel"
Ciò potrebbe semplificarti molto la vita quando scrivi un'istruzione SQL complessa in Ruby.
Un'altra possibilità di fantasia è ...
User.where("id > :id", id: 100)
Questa funzione consente di creare query più comprensibili se si desidera sostituire in più posizioni, ad esempio ...
User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)
Questo ha più significato che avere molto ?
sulla query ...
User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)
Ho spesso questo problema con i campi data (dove gli operatori di confronto sono molto comuni).
Per approfondire ulteriormente la risposta di Mihai, che credo sia un approccio solido.
Ai modelli è possibile aggiungere ambiti come questo:
scope :updated_at_less_than, -> (date_param) {
where(arel_table[:updated_at].lt(date_param)) }
... e poi nel tuo controller, o ovunque tu stia usando il tuo modello:
result = MyModel.updated_at_less_than('01/01/2017')
... un esempio più complesso con join è simile al seguente:
result = MyParentModel.joins(:my_model).
merge(MyModel.updated_at_less_than('01/01/2017'))
Un enorme vantaggio di questo approccio è (a) che consente di comporre le query da ambiti diversi e (b) evita le collisioni alias quando si unisce alla stessa tabella due volte poiché arel_table gestirà quella parte della generazione della query.
Rails 6.1 ha aggiunto una nuova "sintassi" per gli operatori di confronto in where
condizioni, ad esempio:
Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)
Quindi la tua query può essere riscritta come segue:
User.where('id >': 200)
Ecco un link a PR dove puoi trovare altri esempi.
Più breve:
User.where("id > 200")
where("id > ?", 200)
sintassi). Questo non ci riesce.