2012-04-30 119 views
4

Rails 3.1,Ruby 1.9.2,AR/MySQL。Rails每天只保留多条记录中的一条。保留最后一个,删除其余部分

如果同一类型的结果在该期间有很多结果,我正在寻找如何在每个时间段(一天)只保留一个结果的建议。一个例子可能是追踪股票价格。最初,我们会每隔15分钟节省一次价格,但只需要存储1周内的每个单一价格点。在第一周后,我们每天只需要1个价格(最后一个记录,收盘价)。

下面是一个简单的第一次尝试,做的工作,但非常低效的:提前

# stock has many prices, price has one stock 
# get all prices for single stock older than 1 week 
prices = stock.prices.where("created_at < ? ", Time.now-1.week) 
prices.group_by{ |price| price.created_at.to_date }.each do |k,v| # group by day 
    if v.count > 1 # if many price points that day 
    (v[0]..v[v.size-2]).each {|r| r.delete} # delete all but last record in day 
    end 
end 

感谢您的帮助/建议。我会尽力通过更新,希望能帮助某些人。

回答

1

与其说删除每个像

(v[0]..v[v.size-2]).each {|r| r.delete} 

做DELETE_ALL但不是最后的

price_ids_to_keep = [] 
if v.count > 1 # if many price points that day 
    price_ids_to_keep << v[-1].id # get the last 
else 
    price_ids_to_keep << v[0].id 
end 

prices.where('id not in (?)',price_ids_to_keep).delete_all 

我从来没有做过,但我敢肯定它应该工作


这是更好的,因为它会减少DELETE查询,但应该有一种方法可以使所有这些在j最大的一个查询


有了商业眼光,您或您的团队应该更好地思考这个问题。现在存储便宜,像这样的信息对未来的数据挖掘和类似的东西可能是宝贵的。

3

通过在SQL中完成所有操作,并将范围限制为上次运行的范围,可以使其效率更高。另外,如果您添加一列以将旧的结束日期条目标记为“已归档”,则会使查询变得更加简单。存档价格是一周后您不会删除的价格。

rails generate migration add_archived_to_prices archived:boolean 

在迁移之前,请修改迁移到created_at列的索引。

class AddArchivedToPrices < ActiveRecord::Migration 
    def self.up 
    add_column :prices, :archived, :boolean 
    add_index :prices, :created_at 
    end 

    def self.down 
    remove_index :prices, :created_at 
    remove_column :prices, :archived 
    end 
end 

工作流程会去是这样的:

# Find the last entry for each day for each stock using SQL (more efficient than finding these in Ruby) 
keepers = 
    Price.group('stock_id, DATE(created_at)'). 
     having('created_at = MAX(created_at)'). 
     select(:id). 
     where('created_at > ?', last_run) # Keep track of the last run time to speed up subsequent runs 

# Mark them as archived 
Price.where('id IN (?)', keepers.map(&:id)).update_all(:archived => true) 

# Delete everything but archived prices that are older than a week 
Price.where('archived != ?', true). 
     where('created_at < ?", Time.now - 1.week). 
     where('created_at > ?', last_run). # Keep track of the last run time to speed up subsequent runs 
     delete_all 

最后要注意,一定不要group()update_all()结合起来。 group()被忽略update_all()

相关问题