我正在尝试在 Rails 中制作图表,例如给定日期范围内每天的平均销售额
假设我有一个 products_sold 模型,它有一个“sales_price” float 属性。但如果特定日期没有销售额(例如模型/数据库中没有销售额),我只想返回 0。
在 MySQL/Rails 中完成这项工作的最佳方法是什么?我知道我可以做这样的事情:
(这个 SQL 查询可能是获得我想要的东西的完全错误的方式)
SELECT avg(sales_price) AS avg, DATE_FORMAT(created_at, '%m-%d-%Y') AS date
FROM products_sold WHERE merchant_id = 1 GROUP BY date;
得到这样的结果:
| avg | date | 23 01-03-2009 50 01-05-2009 34 01-07-2009 ... ...
我想得到的是:
| avg | date | 23 01-03-2009 0 01-04-2009 50 01-05-2009 0 01-06-2009 34 01-07-2009 0 01-08-2009 ... ...
我可以使用 SQL 执行此操作,还是必须对结果进行后处理以查找日期范围中的哪些日期不在 SQL 结果集中?也许我需要一些子选择或 IF 语句?
感谢大家的帮助。
最佳答案
有什么原因(除了已经提到的日期之外)为什么您不使用 ActiveRecord 中的内置组函数功能?您似乎担心“后处理”,我认为这不是真正值得担心的事情。
您使用的是 Rails,因此您可能应该首先寻找 Rails 解决方案[1]。我的第一个想法是做类似的事情
Product.average(:sales_price, :group => "DATE(created_at)", :conditions => ["merchant_id=?", 1])
ActiveRecord 几乎变成了您描述的 SQL。假设商家和产品之间声明了 has_many
关联,那么使用它可能会更好,例如:
ave_prices = Merchant.find(1).products.average(:sales_price, :group => "DATE(created_at)")
(我希望您将模型描述为“products_sold”是某种转录错误,顺便说一句 - 如果不是,那么您的类命名有点不合时宜!)
毕竟,您回到了起点,但是您以更传统的 Rails 方式到达了那里(Rails 确实重视约定!)。现在我们需要填补空白。
我假设您知道您的日期范围,假设它被定义为从 from_date
到 to_date
的所有日期。
date_aves = (from_date..to_date).map{|dt| [dt, 0]}
将完整的日期列表构建为数组。我们不需要获得平均值的日期:
ave_price_dates = ave_prices.collect{|ave_price| ave_price[0]} # build an array of dates
date_aves.delete_if { |dt| ave_price.dates.index(dt[0]) } # remove zero entries for dates retrieved from DB
date_aves.concat(ave_prices) # add the query results
date_aves.sort_by{|ave| ave[0] } # sort by date
在我看来,这些内容看起来有点困惑:我认为它可以更简洁、更简洁。我会研究构建 Hash 或 Struct,而不是留在数组中。
[1] 我并不是说不要使用 SQL - 确实会出现 ActiveRecord 无法生成最高效查询而您求助于 find_by_sql
的情况。没关系,它应该是那样的,但我认为你应该尝试将它用作最后的手段。
关于sql - MySQL 或 Rails 中在特定日期范围内每天获取 AVG 的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/423212/