Арифметика DateTime в запросе ActiveRecord (PostgreSQL)

У меня есть два столбца datetime в таблице User/users: created_at и birthdate. Я хотел бы найти пользователей, чья дата рождения меньше, чем за 13 лет до даты их создания.

Эквивалентный оператор Rails if будет ((created_at - birthdate) < 13.years)

Как преобразовать это в запрос ActiveRecord (который будет работать на PostgreSQL)? Это вообще возможно, или мне придется перебирать все записи вручную?


person LouieGeetoo    schedule 24.04.2012    source источник


Ответы (2)


Самый простой способ сделать это — использовать интервал, тогда это в значительной степени прямая транслитерация версии Rails:

User.where(%q{created_at - birthdate < interval '13 years'})

Разница между двумя временными метками (или временной меткой и датой) представляет собой интервал, поэтому вам просто нужно соответствующее значение в правой части сравнения.

person mu is too short    schedule 24.04.2012
comment
Это работает. Спасибо! Примечание для всех, кто это читает: interval не работает на SQLite. Мне пришлось войти на мой производственный сервер, используя PostgreSQL, чтобы протестировать его. - person LouieGeetoo; 25.04.2012
comment
@LouieGeetoo: вам действительно не следует разрабатывать и развертывать в разных стеках, небольшая разница в синтаксисе с арифметикой дат будет наименьшей из ваших проблем. - person mu is too short; 25.04.2012

Вам просто нужно сформулировать это в синтаксисе PostgreSQL внутри предложения where.

Для MySQL это будет выглядеть примерно так, используя datediff функция:

User.where("DATEDIFF(created_at, birthdate) > (13 * 365)")

13*356 означает 3 года в днях, поскольку datediff возвращает разницу в днях.

Затем я бы инкапсулировал это в функцию, подобную области действия, например следующую:

class User < ActiveRecord::Model
  def self.age_difference(years)
    where("DATEDIFF(created_at, birthdate) > (? * 365)", years)
  end
end

Итак, вы можете назвать это:

User.age_difference(13).each do |user|
  puts user.inspect
end

Я думаю, это похоже на Postgres.

person Tigraine    schedule 24.04.2012
comment
У вас проблема с високосным годом. - person mu is too short; 24.04.2012
comment
Жизнь слишком коротка для проблем с високосным годом :D .. Я просто предположил, что это не такая уж большая проблема .. - person Tigraine; 24.04.2012
comment
Помимо високосных лет, принято считать, что в году 365 дней, а не 356. ;) В любом случае спасибо за ответ. - person LouieGeetoo; 25.04.2012
comment
@LouieGeetoo: было общепризнано, что двух цифр достаточно, чтобы вместить год... - person mu is too short; 25.04.2012
comment
LouiGeetoo: Упс ;) да, это случается, когда у тебя есть двадцать дел, но вместо этого ты зависаешь в stackoverflow.. - person Tigraine; 25.04.2012