我正在编写一个程序,其中项目具有多个特征和多个值,并且值属于项目和特征。我需要能够多次将值和特征连接到items表(无限次)。
有没有办法通过ruby语法获得看起来像这样的连接表?
SELECT items.*
FROM items
INNER JOIN characteristics ON characteristics.item_id = items.id AS characteristics1
INNER JOIN values ON value_items.item_id = item.id AS value1
INNER JOIN characteristics ON characteristics.item_id = items.id AS characteristics2
INNER JOIN values ON value_items.item_id = item.id AS value2
WHERE characteristics1.id = 1 AND
WHERE values1.value = "foo" AND
WHERE characteristics2.id = 2 AND
WHERE values2.value = "bar"
至少,我实际上需要能够链接无限数量的自联接。
编辑:努力寻求解决方案 - 还没有。
Item.joins(:values).where("values.value=?", "foo").where("values.characteristic_id = 2")
这可以根据其中一个特征找到我的项目。但是,当我尝试查找满足多个特征标准的项目时,我得到ActiveRecord::StatementInvalid: PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type record
当我尝试这两种解决方案时,我得到了这个错误:
Item.joins(:values).where("values.value=?", ["foo", "bar"]).where("values.characteristic_id=?", [1, 2])
Item.includes(:values).where("values.value=?", ["foo", "bar"]).where("values.characteristic_id=?", [1, 2]).references(:values)
答案 0 :(得分:1)
如果你的模特有关系,
Items.includes(:characteristics,:value_items).where('characteristics.id=?',[1,2]).references(:characteristics).where('values_items.value=?',['foo','bar']).references(:value_items)
答案 1 :(得分:0)
创建模型时,Active Record可以利用关联。这将允许您在模型文件中添加has_many和/ belongs_to。见下面的例子。
class Author< ApplicationRecord has_many:书籍,依赖:: destroy 端
class Book< ApplicationRecord belongs_to:作者 端
Rails支持六种类型的关联:
belongs_to
has_one
has_many
has_many :through
has_one :through
has_and_belongs_to_many
答案 2 :(得分:0)
良好的解决方案
我基本上忘记了别名是如何工作的。这就是我想要的:
Item.joins("INNER JOIN values v1 on v1.item_id = items.id")
.joins("INNER JOIN values v2 on v2.item_id = items.id")
.where(v1: {characteristic_id: 1, value: "foo"})
.where(v2: {characteristic_id: 2, value: "bar})
糟糕的解决方案
我在ActiveRecord之外找到了使用ruby的临时解决方案。
search1 = Item.joins(:values).where(values: {characteristic_id: 1, value: "foo"})
search2 = Item.joins(:values).where(values: {characteristic_id: 2, value: "bar"})
Item.find(search1.map(&:id) & search2.map(&:id))
我可能实际上必须递归地执行此操作,因为我无法定义search1和search2变量,因为我需要无限次数的搜索。或者也许是元编程。
但是,在单个查询中执行此操作肯定会更好。也许我只需编写一个生成原始SQL的方法。仍在寻找通过rails获取连接别名的方法。
答案 3 :(得分:0)
好的,这是我的答案,基于Wylliam Judd添加的“ clarification answer”,它表示他正在寻找类似的东西:
Item.joins("INNER JOIN values v1 on v1.item_id = items.id")
.joins("INNER JOIN values v2 on v2.item_id = items.id")
.where(v1: {characteristic_id: 1, value: "foo"})
.where(v2: {characteristic_id: 2, value: "bar"})
还没有人指出INNER JOIN
可以为ON
子句提供多个条件(例如,您可以使用AND
)。
因此,针对此问题的手工编码的SQL答案可以这样完成:
Item.
joins("INNER JOIN values v1 ON v1.item_id = items.id AND v1.characteristic_id = 1 AND v1.value = 'foo'").
joins("INNER JOIN values v2 ON v2.item_id = items.id AND v2.characteristic_id = 2 AND v2.value = 'bar'")
假设您在末尾贴上.all
,将在items
表中获得所有具有2条关联记录的values
条记录,每条记录与{{1 }}和{characteristic_id: 1, value: "foo"}
但是等等!还有更多!
现在我们有了Rails 6,看起来Wylliam的“一厢情愿”代码开箱即用! (我不知道它是否适用于以前的版本,因为我的计算机上仅安装了Rails 6.0.0。)您可以 使用命名的别名(例如{characteristic_id: 2, value: "bar"}
,{{ 1}}),就像他拥有的一样:
v1
如果在结尾处打一个v2
,最终将得到您期望的结果:
.where