我有以下半高级数据库查询,该查询过去10年的每小时价格并返回过去七天的每日平均价格:
averages = Trade.where('date >= ?', 7.days.ago).average(:price, :group => "DATE_TRUNC('day', date - INTERVAL '1 hour')")
这会返回date
(当天)和averageprice
,如下所示:
"2012-12-29 00:00:00"=>#<BigDecimal:7f97932be328,'0.2513458333 33333333E2',27(27)>
然后我遍历每个响应并将它们保存为TradeDailyAverage模型中的新记录。
# Loops through each daily average produced above
averages.each do |date, avg|
# Converts the BigDecimal to Floating Point(?)
averagefloat = avg.to_f
# Rounds the Daily Average to only two decimal points
dailyaverage = number_with_precision(averagefloat, :precision => 2)
# Creates a new Object in the PpDailyAverage table
TradeDailyAverage.create(date: date, averageprice: dailyaverage)
这是有效的,但由于这将是每小时佣金任务,每小时都有新价格,我该如何更改此设置以首先按date
找到TradeDailyAverage,如果是存在,更新averageprice
属性,或创建新记录(如果它不存在)。
在TradeDailyAverage模型上设置Validate_uniqueness。
更新
当我这样做时,会显示7个项目,并且具有准确的平均值。但他们只是赢了。当我添加newaverage.save!
时,我收到&#34;验证错误:已经过了日期!&#34;
newaverage = TradeDailyAverage.find_or_initialize_by_date(date: date)
newaverage.averageprice = dailyaverage
puts newaverage.date
puts newaverage.averageprice
另外,如果我做newaverage.new_record?平均值返回TRUE
答案 0 :(得分:2)
我想你想要这样的东西:
tda = TradeDailyAverage.first_or_initialize(date: date)
tda.averageprice = dailyaverage
tda.save
答案 1 :(得分:0)
问题(感谢Alex的帮助)是由于日期时间不同造成的。保存到PG数据库后,小时数将在日期时间更改。这可能是由于db中的时区问题。因此,上面的代码无法找到现有记录,因为它包含的时间与数据库中保存的时间不同。
由于我生成每日平均值,因此我不需要时间,只需要日期列中的日期。因此,我将日期转换为日期以避免时差问题。我还使用Case更改了代码,以便我可以报告错误。我不认为这是非常有效的,但它现在正在发挥作用。我相信只要将日期时间值转换为.to_date
的日期,Alex的上述解决方案也可以正常工作:
# Loops through each daily average produced above
averages.each do |datetime, avg|
# Converts the BigDecimal to Floating Point(?)
avgfloat = avg.to_f
# Rounds the Daily Average to only two decimal points
avgprice = number_with_precision(avgfloat, :precision => 2)
# Converts datetime to date since this will not work with datetime (PostgreSQL is time-zoned challenged)
avgdate = datetime.to_date
# These are printed to use for testing.
puts avgdate
puts avgprice
# Starts Case to either report an error, update an existing record, or create new.
case
when avgdate.blank? || avgprice.blank?
puts "Something went terribly wrong with your seven day averages producing algorithm."
when TradeDailyAverage.exists?(:date=>avgdate)
updateavg = TradeDailyAverage.find_by_date(avgdate)
updateavg.averageprice = avgprice
updateavg.save
else
TradeDailyAverage.create(:date=>avgdate, :averageprice=>avgprice)
end # Ends Case
end # Ends Loop for each Daily Average