Programing

ActiveRecord 날짜 필드에서 연도, 일 또는 월로 찾기

crosscheck 2020. 11. 16. 07:51
반응형

ActiveRecord 날짜 필드에서 연도, 일 또는 월로 찾기


날짜 속성이있는 ActiveRecord 모델이 있습니다. 해당 날짜 속성을 사용하여 연도, 일 및 월별로 찾을 수 있습니까?

Model.find_by_year(2012)
Model.find_by_month(12)
Model.find_by_day(1)

또는 단순히 find_by_date (2012-12-1)가 가능합니까?

나는 년, 월, 일 속성을 만드는 것을 피할 수 있기를 바랐습니다.


"날짜 속성"이 전체 타임 스탬프가 아니라 날짜라고 가정하면 간단한 where"날짜 별 찾기"를 제공합니다.

Model.where(:date_column => date)

find_by_date_column최대 하나의 결과를 제공하므로 원하지 않습니다 .

extractSQL 함수 를 사용하려는 연도, 월, 일 쿼리의 경우 :

Model.where('extract(year  from date_column) = ?', desired_year)
Model.where('extract(month from date_column) = ?', desired_month)
Model.where('extract(day   from date_column) = ?', desired_day_of_month)

그러나 SQLite를 사용하는 경우 strftime무엇이 무엇인지 알지 못하기 때문에 문제를 해결해야합니다 extract.

Model.where("cast(strftime('%Y', date_column) as int) = ?", desired_year)
Model.where("cast(strftime('%m', date_column) as int) = ?", desired_month)
Model.where("cast(strftime('%d', date_column) as int) = ?", desired_day_of_month)

%m%d형식 지정은 어떤 경우 앞에 0을 추가하고 그 따라서는 평등 테스트를 혼동 할 수 있습니다 cast(... as int)숫자에 형식 문자열을 강제로.

ActiveRecord는 데이터베이스 간의 모든 차이점으로부터 사용자를 보호하지 않으므로 사소하지 않은 작업을 수행하자마자 나만의 이식성 계층을 구축하고 (추악하지만 때로는 필요함) 제한된 데이터베이스 집합에 연결해야합니다 (현실적이지 않은 경우 데이터베이스에서 실행해야하는 무언가를 공개하거나 Ruby에서 모든 로직을 수행합니다 (사소한 양의 데이터에 대해 미쳤습니다).

큰 테이블에서는 년, 월, 일 쿼리가 상당히 느립니다. 일부 데이터베이스에서는 함수 결과에 인덱스를 추가 할 수 있지만 ActiveRecord는이를 이해하기에는 너무 어리석기 때문에 사용하려고하면 큰 혼란을 야기합니다. 따라서 이러한 쿼리가 너무 느리면 피하려는 세 개의 추가 열을 추가해야합니다.

이러한 쿼리를 많이 사용하려는 경우 범위를 추가 할 수 있지만 인수가있는 범위를 추가하는 권장 방법 은 클래스 메서드를 추가하는 것입니다.

클래스 메소드를 사용하는 것이 범위에 대한 인수를 허용하는 선호되는 방법입니다. 이러한 메서드는 연결 개체에서 계속 액세스 할 수 있습니다.

따라서 다음과 같은 클래스 메서드가 있습니다.

def self.by_year(year)
    where('extract(year from date_column) = ?', year)
end
# etc.

데이터베이스 독립 버전 ...

def self.by_year(year)
  dt = DateTime.new(year)
  boy = dt.beginning_of_year
  eoy = dt.end_of_year
  where("published_at >= ? and published_at <= ?", boy, eoy)
end

MySQL의 경우 이것을 시도하십시오.

Model.where("MONTH(date_column) = 12")
Model.where("YEAR(date_column) = 2012")
Model.where("DAY(date_column) = 24")

모델에서 :

scope :by_year, lambda { |year| where('extract(year from created_at) = ?', year) }

컨트롤러에서 :

@courses = Course.by_year(params[:year])

이를 수행하는 가장 쉬운 방법은 범위라고 생각합니다.

scope :date, lambda {|date| where('date_field > ? AND date_field < ?', DateTime.parse(date).beginning_of_day, DateTime.parse(date).end_of_day}

다음과 같이 사용하십시오.

Model.date('2012-12-1').all

그러면 보내는 날짜의 시작과 끝 사이에 date_field가있는 모든 모델이 반환됩니다.


이 시도:

Model.where("MONTH(date_column) = ? and DAY(date_column) = ?", DateTime.now.month, DateTime.now.day)

1 년을위한 간단한 구현

app/models/your_model.rb

scope :created_in, ->( year ) { where( "YEAR( created_at ) = ?", year ) }

용법

Model.created_in( 1984 )

나는 BSB의 대답을 좋아하지만 범위로

scope :by_year, (lambda do |year| 
  dt = DateTime.new(year.to_i, 1, 1)
  boy = dt.beginning_of_year
  eoy = dt.end_of_year
  where("quoted_on >= ? and quoted_on <= ?", boy, eoy)
end)

이것은 또 다른 것입니다.

def self.by_year(year)
  where("published_at >= ? and published_at <= ?", "#{year}-01-01", "#{year}-12-31")
end

SQLite에서 나를 위해 꽤 잘 작동합니다.


extract방법이 필요하지 않습니다 . 이것은 postgresql의 매력처럼 작동합니다.

text_value = "1997" # or text_value = '1997-05-19' or '1997-05' or '05', etc
sql_string = "TO_CHAR(date_of_birth::timestamp, 'YYYY-MM-DD') ILIKE '%#{text_value.strip}%'"
YourModel.where(sql_string)

아래와 같이 또 다른 짧은 범위 :

  class Leave
    scope :by_year, -> (year) {
      where(date:
                Date.new(year).beginning_of_year..Date.new(year).end_of_year)
    }
  end

범위를 호출하십시오.

Leave.by_year(2020)

참고 URL : https://stackoverflow.com/questions/9624601/activerecord-find-by-year-day-or-month-on-a-date-field

반응형