我对SQL和Arel非常糟糕。我甚至不知道Arel是什么或如何使用它。有没有一个很好的资源呢?
我有一个问题,我不知道为什么花了这么长时间。也许人们可以指出为什么这需要我这么长时间。
无论如何,我有一个Products
表和一个Restrictions
表。产品可能有很多限制。限制是美国的州。我的大多数产品没有任何限制,但我的一个产品有限制(它不能出售在" CT"因为" CT"有疯狂的法律)。
我想退回所有对CT没有限制的产品。但是,此查询无效:
Product.joins(:restrictions).where.not(restrictions: { name: "CT" }).count
所以我希望能够退回我的所有产品,除了对CT有限制的产品。但是,它什么都不返回:
Product.last.restrictions
Product Load (0.5ms) SELECT "products".* FROM "products" ORDER BY "products"."id" DESC LIMIT 1
Restriction Load (0.3ms) SELECT "restrictions".* FROM "restrictions" INNER JOIN "product_restrictions" ON "restrictions"."id" = "product_restrictions"."restriction_id" WHERE "product_restrictions"."product_id" = $1 [["product_id", 2559]]
[
#<Restriction:0x007ff0f1dfec58> {
:id => 11,
:category => "US State",
:name => "CT",
:created_at => Wed, 07 Jun 2017 17:57:42 UTC +00:00,
:updated_at => Wed, 07 Jun 2017 17:57:42 UTC +00:00
}
]
[48] pry(main)> Product.count
(0.6ms) SELECT COUNT(*) FROM "products"
2494
[49] pry(main)> Product.joins(:restrictions).where.not(restrictions: { name: "AZ" }).count
(47.8ms) SELECT COUNT(*) FROM "products" INNER JOIN "product_restrictions" ON "product_restrictions"."product_id" = "products"."id" INNER JOIN "restrictions" ON "restrictions"."id" = "product_restrictions"."restriction_id" WHERE ("restrictions"."name" != $1) [["name", "AZ"]]
1
[50] pry(main)> Product.joins(:restrictions).where.not(restrictions: { name: "CT" }).count
(6.7ms) SELECT COUNT(*) FROM "products" INNER JOIN "product_restrictions" ON "product_restrictions"."product_id" = "products"."id" INNER JOIN "restrictions" ON "restrictions"."id" = "product_restrictions"."restriction_id" WHERE ("restrictions"."name" != $1) [["name", "CT"]]
0
我预计最后一个查询返回2493(只有最后一个产品有限制),而不是0.我希望AZ查询返回2494而不是0。
但是,这个引擎sql工作(使用NOT EXISTS):
state = "CT"
Product.where('NOT EXISTS ' \
'(SELECT 1 from restrictions
JOIN product_restrictions
on product_id = products.id
WHERE restrictions.name = ? AND restrictions.category = ?)', state, 'US State'
)
}
aboe查询返回所有产品,除了具有CT限制的产品外
问题
答案 0 :(得分:0)
当您进行INNER JOIN时,它会创建一个连接表,其中只有具有相关限制的产品才有条目。 “没有限制的产品”或“没有product_id的限制”将不包括在内。
在你提到的问题中,“只有最后一个产品有限制”。因此,当您执行JOIN时,它在连接表中只创建了一个条目,当您在限制名称上进一步添加条件时,您就摆脱了它。因此最终结果是空的。
如果您想在连接表中包含产品,即使它们没有相关的限制,请使用LEFT OUTER JOIN。 这是一个有用的链接 - Inner Join vs Left Outer Join
解决方案: 如果使用rails5: -
Product.left_outer_joins(:restrictions).where.not(restrictions: { name: "CT" }).count
否则
Product.joins("LEFT OUTER JOIN restrictions on restrictions.product_id = products.id").where.not(restrictions: { name: "CT" }).count