【问题标题】:where.not with where in rails/activerecord excluding all records?where.not with where in rails/activerecord 不包括所有记录?
【发布时间】:2020-05-05 21:23:03
【问题描述】:

我有一个模型(配对),它具有长度和日期属性(以及其他属性)。我正在尝试查询所有不涉及特定日期或日期范围的配对,同时匹配配对的其他属性。所有其他查询的代码都可以正常工作,但我的 where.not 排除了所有记录。这是因为(我认为)我构建关系/查询的方式。

我需要排除所选日期范围并匹配长度的内容。这需要叠加在其他范围内的查询上。

关于如何实现这一点的任何想法?

提前致谢!

控制器代码:

rel = rel.other scoped queries
@all_trip_len.each do |len|
 rel = rel.date_selector(@date_sel_1, @date_start_1, @date_end_1, len)
end
rel = rel.more scoped queries

模型范围:

def self.date_selector(sel, start_d, end_d, length)
 # Need to get all possible start dates that could touch avoid days for each length of trip
 rel = self
 start = Date.parse(start_d) - (length.to_i - 1)
 rel = rel.where.not(date: start.to_s..Date.parse(end_d).to_s).where(length: length)            
 return rel
end

我收到的查询是:

SELECT "pairings".* 
FROM "pairings" 
WHERE "pairings"."bid_month_id" = $1 
  AND NOT ("pairings"."date" BETWEEN $2 AND $3) 
  AND "pairings"."length" = $4 
  AND NOT ("pairings"."date" BETWEEN $5 AND $6) 
  AND "pairings"."length" = $7 [["bid_month_id", 8], ["date", "2020-04-08"], ["date", "2020-04-08"], ["length", 1], ["date", "2020-04-07"], ["date", "2020-04-08"], ["length", 2]

我需要更多类似的东西:

SELECT "pairings".* 
FROM "pairings" 
WHERE "pairings"."bid_month_id" = $1 
  AND NOT (("pairings"."date" BETWEEN $2 AND $3) 
           AND "pairings"."length" = $4) 
  AND NOT (("pairings"."date" BETWEEN $5 AND $6) 
           AND "pairings"."length" = $7) [["bid_month_id", 8], ["date", "2020-04-08"], ["date", "2020-04-08"], ["length", 1], ["date", "2020-04-07"], ["date", "2020-04-08"], ["length", 2]

编辑:

在 MurifoX 的帮助下,我走得更远了。查询的构建几乎正确,但我需要在 pairing.date 分组之间进行 OR。

我现在拥有的:

SELECT "pairings".* 
FROM "pairings" 
WHERE "pairings"."bid_month_id" = $3 
  AND (((date <= '2020-04-06' AND date >= '2020-04-07') AND length = 1)) 
  AND (((date <= '2020-04-05' AND date >= '2020-04-07') AND length = 2))

我需要什么:

SELECT "pairings".* 
FROM "pairings" 
WHERE "pairings"."bid_month_id" = $3 
  AND (((date <= '2020-04-06' AND date >= '2020-04-07') AND length = 1) 
       OR ((date <= '2020-04-05' AND date >= '2020-04-07') AND length = 2))

我尝试过使用 rails 5 或 (rel.or(Pairing.date_selector(xxx)) 但这不起作用,因为它会将所有 where AND 转换为 OR,而我只需要配对/日期分组之间的 OR。还需要日期分组周围的括号。

【问题讨论】:

    标签: ruby-on-rails activerecord


    【解决方案1】:

    使用 ActiveRecord 方法构建半复杂查询有时会很棘手,所以在这种特殊情况下,我总是告诉人们手动完成:

    rel = self
    start = Date.parse(start_d) - (length.to_i - 1)
    rel = rel.where("((date <= ? AND date >= ?) AND length = ?)", start.to_s, Date.parse(end_d).to_s, length)
    return rel
    

    【讨论】:

    • 这让我非常接近。我想我需要在不同的日期/长度查询之间有一个 OR 语句(现在是一个 AND)。知道如何实现吗? SELECT "pairings".* FROM "pairings" WHERE "pairings"."bid_month_id" = $3 AND (((date &lt;= '2020-04-06' AND date &gt;= '2020-04-07') AND length = 1)) AND (((date &lt;= '2020-04-05' AND date &gt;= '2020-04-07') AND length = 2))
    • @ATP_coder Rails 也有 OR,看看这个:blog.bigbinary.com/2016/05/30/…
    • 不幸的是,这也不起作用。我在这里问我的问题之前经历了那个。它为您所做的所有关系/范围创建一个 OR。我仍然需要一些AND。在下面回答了我的Q。感谢您让我朝着正确的方向开始!
    【解决方案2】:

    我最终不得不将其构建为一个字符串,以使其完全按照我的意愿行事。 rails 5 中的 or 关系创建了一个语句,该语句将我以前的所有范围子句与新的(所有 AND -> OR)进行 OR 运算,并且我需要所有以前的范围查询都有效,并且只需要对新日期进行 OR'd .

    def exclude_dates(rel, date_start_1, date_end_1, all_trip_len)
        dates_query = String.new
        count = 0 
        all_trip_len.each do |len|
         start_d = Date.parse(date_start_1) - (len.to_i - 1)
         end_d = Date.parse(date_end_1)
         count += 1
         dates_query += " OR " if count > 1
         dates_query += "((date < '#{start_d.to_s}' OR date > '#{end_d.to_s}') AND length = '#{len}')"
        end
    rel = rel.where(dates_query)
    end
    

    这创建了我需要的查询。希望有更多的“rails”方式来做到这一点......

    
    SELECT COUNT(*) FROM "pairings" WHERE "pairings"."bid_month_id" = $1 AND (((date < '2020-04-02' OR date > '2020-04-02') AND length = '1') OR ((date < '2020-04-01' OR date > '2020-04-02') AND length = '2') OR ((date < '2020-03-31' OR date > '2020-04-02') AND length = '3') OR ((date < '2020-03-30' OR date > '2020-04-02') AND length = '4')) AND (((date < '2020-04-14' OR date > '2020-04-17') AND length = '1') OR ((date < '2020-04-13' OR date > '2020-04-17') AND length = '2') OR ((date < '2020-04-12' OR date > '2020-04-17') AND length = '3') OR ((date < '2020-04-11' OR date > '2020-04-17') AND length = '4'))  [["bid_month_id", 8]]
    
    

    感谢 @MurifoX 让我在日期方面朝着正确的方向前进!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      相关资源
      最近更新 更多