假设我有一个复杂的公式来计算小部件的质量
quality = 0.4(factory_quality) + 0.3(1/days_since_manufacture) + 0.3(materials_quality)
这三个因素本身就是函数,需要与工厂表进行连接,可能还需要连接一个物料清单与材料的连接表,其中相关记录被平均或其他操作。
在Rails项目中,架构上如何管理这个问题? a) 如何产生正确的查询和 b) 如何管理Rails代码?
目前对于SQL,我正在使用FROM语句中的子查询:
SELECT *,
(0.4 * factory_quality + 0.3 * (1/days_since_manufacture) + 0.3 * materials_quality) AS quality
FROM (
SELECT *,
((factories.last_inspection_score + factories.variance_score)/2) AS factory_quality,
(now() - widgets.created_at) AS days_since_manufacture,
SUM(materials.quality_score) AS materials_quality
FROM widgets,
JOIN factories ON widget.factory_id = factories.id
JOIN bills_of_materials ON widget.id = bills_of_materials.widget_id
JOIN materials ON bills_of_materials.material_id = materials.id
GROUP BY widgets.id
) AS widgets;
在Rails中,我主要使用ActiveRecord实现了这个功能:
class Widget < ActiveRecord::Base
belongs_to :factory
has_many :bills_of_material
has_many :materials, through :bills_of_material
class << self
def with_quality
select([
"widgets.*",
"(0.4 * factory_quality + 0.3 * (1/days_since_manufacture) + 0.3 * materials_quality) AS quality"
].join(",")
.from("(#{subquery}) AS widgets")
end
private
def subquery
select([
"widgets.*",
"((factories.last_inspection_score + factories.variance_score)/2) AS factory_quality",
"(now() - widgets.created_at) AS days_since_manufacture",
"SUM(materials.quality_score) AS materials_quality"
].join(","))
.joins(:factory,:materials)
.group("widgets.id")
.to_sql
end
end
end
话虽如此,我觉得我可以在Postgres中创建一个自定义函数,在该函数中移动所有这些SQL语句,进行迁移,并清理Rails的代码,使其看起来像:
def with_scores
select("*,quality_score_func(id) AS quality")
end
或类似的东西,但我觉得通过数据库迁移来管理一个不断变化的公式将会很麻烦,更不用说找出当前公式的形式(而且难以测试)。
其他人是如何解决这个问题的?有什么建议或提示吗?