Rails Raw SQL WHERE子句

时间:2014-07-06 03:42:37

标签: sql ruby-on-rails ruby postgresql

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

2 个答案:

答案 0 :(得分:2)

你的问题是你实际上只是在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 < '2014-07-01'

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

除此之外:trainings.date实际代表什么?这个名字非常含糊......

答案 1 :(得分:0)

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

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

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

解决方案是使用date列来存储日期,而不是时间戳。然后你就没有时区,时间,......问题。