【问题标题】:Problems with SQL, Arel and filtering out records. Rails. Could use some adviceSQL、Arel 和过滤记录的问题。导轨。可以使用一些建议
【发布时间】:2017-06-08 19:33:00
【问题描述】:

我在 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。

但是,这个 hood 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 中有限制的产品

问题

  1. 为什么我使用联接的第一个查询不起作用?
  2. 我怎样才能在这里变得更好?有没有关于sql的好书?
  3. 有没有更好的方法来编写不使用类似 SQL 字符串的解决方案?

【问题讨论】:

    标签: sql ruby-on-rails activerecord


    【解决方案1】:

    当您执行 INNER JOIN 时,它会创建一个连接表,其中将包含仅针对具有相关限制的产品的条目。 “没有限制的产品”或“没有product_id的限制”将不包括在内。

    在您提到的问题中,“只有最后一种产品有限制”。因此,当您执行 JOIN 时,它仅在连接表中创建了 1 个条目,而当您进一步添加限制名称的条件时,您就摆脱了它。因此最终结果为空。

    如果您想在连接表中包含产品,即使它们没有关联的限制,请使用 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
    

    【讨论】:

    • Rails 4 怎么样?
    • else 适用于所有 Rails 版本
    猜你喜欢
    • 2020-10-05
    • 2010-10-17
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多