Parte de por qué Amo a Rails es que odio el SQL, creo que es más como un lenguaje ensamblador que debe manipularse con herramientas de nivel superior como ActiveRecord. Sin embargo, parece que llegué a los límites de este enfoque y estoy fuera de mi profundidad con el SQL.Consulta de carriles complejos: ¿uniones? Sub-seleccionar? ¿Todavía puedo usar named_scope?
Tengo un modelo complejo con muchos sub-registros. También tengo un conjunto de 30-40 named_scopes que implementan la lógica comercial del cliente. Estos ámbitos se encadenan de forma condicional, por lo que tengo esos ámbitos joins_
, por lo que las uniones no se ven afectadas.
Tengo un par de ellas que no funcionan bien, o al menos no como el cliente quiere que trabajen. Aquí hay una idea aproximada de la estructura del modelo, con algunos ámbitos nombrados (no todos necesarios para el ejemplo) que ilustran mi enfoque e indican mis problemas. (Por favor, perdona los errores de sintaxis)
class Man < ActiveRecord::Base
has_many :wives
named_scope :has_wife_named lambda { |n| { :conditions => { :wives => {:name => n}}}}
named_scope :has_young_wife_named lambda { |n| { :conditions => { :wives => {:name => n, :age => 0..30}}}}
named_scope :has_yw_named_v2 lambda { |n| { :conditions => ["wives.name = ? AND wives.age <= 30", n]}}
named_scope :joins_wives :joins => :wives
named_scope :has_red_cat :conditions => { :cats => {:color => 'red'}}
named_scope :has_cat_of_color lambda { |c| { :conditions => { :cats => {:color => c}}}}
named_scope :has_7yo_cat :conditions => { :cats => {:age => 7}}
named_scope :has_cat_of_age lambda { |a| { :conditions => { :cats => {:age => a}}}}
named_scope :has_cat_older_than lambda { |a| { :conditions => ["cats.age > ?", a] }}
named_scope :has_cat_younger_than lambda { |a| { :conditions => ["cats.age < ?", a] }}
named_scope :has_cat_fatter_than lambda { |w| { :conditions => ["cats.weight > ?", w] } }
named_scope :joins_wives_cats :joins => {:wives => :cats}
end
class Wife < ActiveRecord::Base
belongs_to :man
has_many :cats
end
class Cat < ActiveRecord::Base
belongs_to :wife
end
que puedo encontrar hombres cuyas esposas tienen gatos que son el rojo y siete años de edad
@men = Man.has_red_cat.has_7yo_cat.joins_wives_cats.scoped({:select => 'DISTINCT men'})
Y puedo incluso encontrar los hombres cuyas mujeres tienen gatos de más de 20 libras y mayores de 6 años
@men = Man.has_cat_fatter_than(20).has_cat_older_than(5).joins_wives_cats.scoped({:select => 'DISTINCT men'})
Pero eso no es así lo que quiero. Quiero encontrar a los hombres cuyas esposas tengan entre ellos al menos un gato rojo y un gato de siete años, que no tiene que ser el mismo gato, o encontrar a los hombres cuyas esposas tengan al menos un gato por encima de un peso determinado y un gato más viejo que una edad determinada.
(en los ejemplos posteriores, por favor suponer la presencia de la apropiadajoins_
yDISTINCT
)puedo encontrar hombres con esposas llamada Esther
@men = Man.has_wife_named('Esther')
Incluso puedo encontrar hombres con esposas llamada Esther, Ruth O Ada (dulce!)
@men = Man.has_wife_named(['Esther', 'Ruth', 'Ada'])
pero quiero encontrar hombres con esposas llamada Esther, Ruth y Ada.
Ja, ja, solamente en broma, en realidad, necesito esto: no puedo encontrar hombres con esposas menores de 30 años llamada Esther
@men = Man.has_young_wife_named('Esther')
encontrar a los hombres con las mujeres jóvenes llamada Ester, Rut o Ada
@men = Man.has_young_wife_named(['Esther', 'Ruth', 'Ada'])
pero como arriba quiero encontrar hombres con mujeres jóvenes llamadas Esther AND Ruth AND Ada. Afortunadamente, el mínimo se soluciona en este caso, pero sería bueno especificar también una edad mínima.
hay una manera para probar una desigualdad con una sintaxis de hash, o qué siempre tienen que volver a
:conditions => ["", n]
- tenga en cuenta la diferencia entrehas_young_wife_named
yhas_yw_named_v2
- Me gusta el primero mejor, pero el rango sólo funciona para finita valores. Si está buscando una esposa vieja, creo que podría usara..100
, pero luego, cuando una esposa cumpla 101 años, abandonará la búsqueda. (hmm.¿Ella puede cocinar? j/k)¿hay alguna manera de utilizar un alcance dentro de un alcance? Me encantaría que
:has_red_cat
pudiera usar:has_cat_of_color
de alguna manera, o si hubiera alguna forma de usar el alcance desde un registro secundario en su padre, para poder poner los ámbitos relacionados con el gato en el modeloWife
.
Realmente no quiero hacer esto en SQL sin necesidad de aplicar named_scope
, a menos que haya algo más en realidad más bonito - sugerencias para plugins y otras cosas muy apreciadas, o dirección en el tipo de SQL que necesitaré aprender. Un amigo sugirió que las UNIONES o sub-búsquedas funcionarían aquí, pero esas no parecen ser discutidas mucho en el contexto de Rails. Todavía no sé nada sobre vistas, ¿serían útiles? ¿Hay una manera feliz de hacerlos?
¡Gracias!
Como yo iba a St. Ives
me encontré con un hombre con siete esposas
Cada mujer tenía siete capturas
Cada saco tenía siete gatos
Cada gato tenía siete kits
Kits, gatos, sacos, esposas
¿Cuántos iban a St Ives?
Es una pregunta realmente interesante en abstracto. Y entiendo que los nombres de su modelo y el alcance se derivan de una canción de cuna. Pero es ofensivo, para mí. Esposa: pertenece_ a Hombre? ¿Seriamente? –
Sí, pensé en eso cuando lo estaba escribiendo, pero el poema se me vino a la mente y no pude deshacerme de él. –
Me gustaría encontrar una buena manera de hacer 'UNION's en ámbitos con nombre en AR. Sé que puedes hacerlo en SQLAlchemy. – mikelikespie