我尝试实现对激光数据库的免费请求。例如:给所有能量> 20J,持续时间<150fs和...
的镜头我的方法是先找到所有能量> 20J的镜头,然后将持续时间<150fs的条件应用于这些镜头。依此类推,直到处理完所有搜索参数为止。
ss.ssps.each do |ssp|
selectedShots =
selectedShots.where("instancevalues.name = '#{ssp.instancevalue_name}'")
.where("instancevalues.data_numeric #{ssp.operator} #{ssp.value}")
end
这对于一个搜索参数可以正常工作。 SQL语句如下:
SELECT `shots`.* FROM `shots` WHERE (instancevalues.name = 'Energy')
AND (instancevalues.data_numeric > 20.0)
使用两个搜索参数,我希望Rails首先处理第一个参数并创建上述镜头的子集。之后,应用第二个参数。
相反,Rails生成一个以下形式的SQL语句
SELECT `shots`.* FROM `shots` WHERE
(instancevalues.name = 'Energy')
AND (instancevalues.data_numeric > 20.0)
AND (instancevalues.name = 'Duration')
AND (instancevalues.data_numeric < 150.0)
结果当然是空的。 如何在Rails中实现逐步过滤?
更新:
我试图解释问题的实质,所以我没有使用模型的细节。但是也许这种简化阻碍了其他解决方案。
我有模特:
class Shot < ActiveRecord::Base
belongs_to :experement
has_many :instancevaluesets
has_many :instances, :through => :instancevaluesets
has_many :instancevalues, :through => :instancevaluesets
class Instancevalueset < ActiveRecord::Base
belongs_to :shot
belongs_to :instance
has_many :instancevalues
class Instancevalue < ActiveRecord::Base
# instancevalueset_id :integer(38) not null
# name :string(256) not null
# data_numeric :decimal(, )
belongs_to :instancevalueset
每次激光发射后,将在db中创建一个新镜头。 模型Instancevalueset模型将镜头连接到设备(实例)。拍摄后,物理设备会在此处为自己创建一个条目。设备使用instancevaluesset_id als FK将测量结果写入instancevalues中。我的任务是找到可以满足应用于intancevalues(测量结果)的搜索参数的镜头。
我的原始代码是:
ss.ssps.each do |ssp|
selectedShots = **selectedShots.joins(:instancevalues)**
.where("instancevalues.name = '#{ssp.instancevalue_name}'")
.where("instancevalues.data_numeric #{ssp.operator} #{ssp.value}")
end
假设一组镜头[a,b,c,d,e,f]。镜头[a,c,e]的能量> 20J,所以经过1 ssp之后,我想获得[a,c,e]。现在,我想从该组中滤除短脉冲。射程e为长T = 200fs。因此,在第二次迭代中,我想将ssp应用于[a,c,e]并获得[a,c]。
@Mark的想法很好,但是它返回的查询数组适用于数据库而不是先前的查询。
selectedShots = ss.ssps.map do |ssp|
selectedShots.joins(:instancevalues)
.where("instancevalues.name = '#{ssp.instancevalue_name}'")
.where("instancevalues.data_numeric #{ssp.operator} #{ssp.value}")
end
如果可以对数组执行AND合并,则可以解决我的问题。但是如果我测试:
selectedShots.last.merge(selectionShots.first)
我再次得到:
....WHERE (instancevalues.name = 'Energy')
AND (instancevalues.data_numeric > 20.0)
AND (instancevalues.name = 'Duration')
AND (instancevalues.data_numeric < 150.0)
答案 0 :(得分:0)
我认为这可能有效:
selectedShots = ss.ssps.map do |ssp|
selectedShots.where("instancevalues.name = '#{ssp.instancevalue_name}'")
.where("instancevalues.data_numeric #{ssp.operator} #{ssp.value}")
end
这将为集合ssps中的每个ssp创建一个具有单独条目的数组,并将分别执行每个查询。
答案 1 :(得分:0)
遵循@Mark的建议:
#2D array, one row contain ids of one query
selectedShotsIDs = ss.ssps.map do |ssp|
selectedShots.joins(:instancevalues)
.where("instancevalues.name = '#{ssp.instancevalue_name}'")
.where("instancevalues.data_numeric #{ssp.operator} #{ssp.value}").select(:id).map{|shot| shot.id}
end
# Filter IDs that occur in all queries using array intersections
filteredIDs = selectedShotsIDs.first
selectedShotsIDs.each do |ss|
filteredIDs = filteredIDs & ss
end
# get the shots
selectedShots = Shot.where(id: filteredIDs )
可能效率低下,但有效!