Rails Unlimited Self加入Alias

时间:2016-07-26 05:46:47

标签: sql ruby-on-rails ruby postgresql

我正在编写一个程序,其中项目具有多个特征和多个值,并且值属于项目和特征。我需要能够多次将值和特征连接到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)

4 个答案:

答案 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