【问题标题】:Rails Raw SQL WHERE clauseRails 原始 SQL WHERE 子句
【发布时间】:2014-07-06 03:42:37
【问题描述】:

我在 Rails 中对我的 PG 数据库进行原始 sql 查询。当我在 WHERE 子句中只使用一个日期条件时,效果很好,但是当我使用 2 个日期条件时,它不能按预期工作。要查看结果,我会通过结果对象对每个结果执行一次并将其打印到控制台。

只有一个条件:

connection = ActiveRecord::Base.connection()
results = connection.execute("SELECT * 
                              FROM training_employees 
                              LEFT JOIN trainings 
                              ON training_employees.training_id = trainings.id 
                              WHERE trainings.date >='2014-06-29'")
results.each do |row|
  puts row
end

返回

{"id"=>"1", "employee_id"=>"2", "training_id"=>"1", 
 "created_at"=>"2014-06-29 06:44:13.261074", 
 "updated_at"=>"2014-06-29 06:44:13.261074", 
 "name"=>"Incendios", "date"=>"2014-06-30 02:43:00", 
 "expected_attendance"=>"20", "service_company_id"=>"1"}
{"id"=>"1", "employee_id"=>"3", "training_id"=>"1", 
 "created_at"=>"2014-06-29 06:44:13.261074", 
 "updated_at"=>"2014-06-29 06:44:13.261074", 
 "name"=>"Incendios", 
 "date"=>"2014-06-30 02:43:00", 
 "expected_attendance"=>"20", "service_company_id"=>"1"}
{"id"=>"1", "employee_id"=>"7", "training_id"=>"1", 
 "created_at"=>"2014-06-29 06:44:13.261074", 
 "updated_at"=>"2014-06-29 06:44:13.261074", 
 "name"=>"Incendios", "date"=>"2014-06-30 02:43:00", 
 "expected_attendance"=>"20", "service_company_id"=>"1"}
{"id"=>"1", "employee_id"=>"9", "training_id"=>"1", 
 "created_at"=>"2014-06-29 06:44:13.261074", 
 "updated_at"=>"2014-06-29 06:44:13.261074", 
 "name"=>"Incendios", "date"=>"2014-06-30 02:43:00", 
 "expected_attendance"=>"20", "service_company_id"=>"1"}
{"id"=>"1", "employee_id"=>"10", "training_id"=>"1", 
 "created_at"=>"2014-06-29 06:44:13.261074", 
 "updated_at"=>"2014-06-29 06:44:13.261074", 
 "name"=>"Incendios", "date"=>"2014-06-30 02:43:00", 
 "expected_attendance"=>"20", "service_company_id"=>"1"}
=> #<PG::Result:0x007fa8b9cfc038 
@connection=#<PG::Connection:0x007fa8b994fcf0 
              @socket_io=nil, @notice_receiver=nil, 
              @notice_processor=nil>> 

当我使用两个条件进行查询时

results = connection.execute("SELECT * 
                              FROM training_employees 
                              LEFT JOIN trainings 
                              ON training_employees.training_id = trainings.id 
                              WHERE trainings.date >='2014-06-29' 
                              AND trainings.date <='2014-06-30'")
results.each do |row|
  puts row
end

只返回这个,而不是像一个条件那样返回记录列表

 => #<PG::Result:0x007fa8b75c5398 
      @connection=#<PG::Connection:0x007fa8b994fcf0 @socket_io=nil, 
                    @notice_receiver=nil, @notice_processor=nil>> 

我已经单独测试了条件并返回了我期望的结果(日期范围之间存在记录)

这些是我的模型

Training(id: integer, name: string, date: datetime, 
         expected_attendance: integer, created_at: datetime, 
         updated_at: datetime, service_company_id: integer) 
TrainingEmployee(id: integer, employee_id: integer, 
                 training_id: integer, created_at: 
                 datetime, updated_at: datetime) 

我正在使用 ruby​​ 2.1.1 和 Rails 4.1.0。

【问题讨论】:

    标签: sql ruby-on-rails ruby postgresql


    【解决方案1】:

    您的问题是您实际上只是在 30 日的午夜。当您的类型被转换以进行比较时,您的查询实际上如下所示:

    SELECT * 
    FROM training_employees 
    LEFT JOIN trainings 
           ON training_employees.training_id = trainings.id 
    WHERE trainings.date >='2014-06-29 00:00:00.000000' 
          AND trainings.date <='2014-06-30 00:00:00.000000'
    

    ....所以当然不会包含来自trainingsdate = "2014-06-30 02:43:00" 的记录。查询日期/时间/时间戳的正确方法是使用exclusive upper bound - 即trainings.date &lt; '2014-07-01'

    这也会导致根本不返回任何记录,因为您实际上没有LEFT JOIN,您实际上有一个INNER JOIN。这就是为什么;当WHERE 子句滚动时,任何 LEFT JOINed 并且没有记录的东西都会使这些条件null 并导致数据库排除它们。如果您确实需要LEFT JOIN,则需要将条件移至ON 子句。如果您确实需要INNER JOIN,您应该仍然将它们移到ON 子句,因为它使连接更加明显。

    旁白:trainings.date 实际上代表什么?这是一个非常模棱两可的名字......

    【讨论】:

    • trainings.date 表示提供培训的日期。谢谢!
    • @rcrivera - 那么它应该被命名为offered_Onoffered_At (如果包含时间信息,这个更可能)。一般来说,尽量避免变量/列名的类型。 (有几件事似乎包含了这些信息,但并不完全如此,例如calendar_datebusiness_date,其中“日期”是一个难以避免的概念)。
    【解决方案2】:

    date 中的所有时间戳实际上都大于 2014-06-30,因为所有五个都是:

    "date"=>"2014-06-30 02:43:00"
    

    2014-06-30 的日期对应于2014-06-30 00:00:00 的时间戳,因此您的时间戳的时间部分会干扰您的查询逻辑。

    解决方案是使用date 列来存储日期,而不是时间戳。这样您就不会遇到任何时区、时间等问题。

    【讨论】:

      猜你喜欢
      • 2023-01-29
      • 2016-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-30
      • 2023-03-31
      相关资源
      最近更新 更多