Rails : where 문보다 크거나 작음


142

ID가 200보다 큰 모든 사용자를 찾으려고하지만 특정 구문에 문제가 있습니다.

User.where(:id > 200) 

User.where("? > 200", :id) 

둘 다 실패했습니다.

어떤 제안?

답변:


276

이 시도

User.where("id > ?", 200) 

1
Ernie Miller의 Squeel gem도 확인하십시오
cpuguy83

7
?인라인하는 대신을 사용하는 것을 선호하는 이유가 200있습니까?
davetapley

20
자동 200 이스케이프 (가능 사용자가 값을 입력 할 수 있었다 그것은 SQL 인젝션 공격의 가능성을 방지)
user1051849

124

나는 이것을 Rails 4에서만 테스트했지만 where이 동작을 얻기 위해 해시가 있는 범위를 사용하는 흥미로운 방법 이 있습니다.

User.where(id: 201..Float::INFINITY)

SQL을 생성합니다

SELECT `users`.* FROM `users`  WHERE (`users`.`id` >= 201)

보다 적은 수로 동일하게 수행 할 수 있습니다 -Float::INFINITY.

방금 날짜 를 SO로 작성 하는 것에 대해 묻는 비슷한 질문을 방금 게시했습니다 .

>= vs >

사람들이 코멘트 대화를 파헤 치고 따라야하는 것을 피하기 위해 여기에 하이라이트가 있습니다.

위의 방법은 >=쿼리가 아닌을 생성 합니다 >. 이 대안을 처리하는 방법에는 여러 가지가 있습니다.

불연속 숫자

number_you_want + 1위와 같은 전략을 사용하여 사용자에게 관심이 id > 200있지만 실제로는를 찾을 수 id >= 201있습니다. 단일 관심 단위로 증가시킬 수있는 정수 및 숫자에 적합합니다.

잘 이름이 지정된 상수로 추출한 숫자가 있으면 한 눈에 읽고 이해하기가 가장 쉬울 수 있습니다.

역 논리

우리는 그 사실을 x > y == !(x <= y)사용하고 체인이 아닌 곳을 사용할 수 있습니다 .

User.where.not(id: -Float::INFINITY..200)

SQL을 생성하는

SELECT `users`.* FROM `users` WHERE (NOT (`users`.`id` <= 200))

읽기 및 추론에 약간의 시간이 걸리지 만 + 1전략을 사용할 수없는 불연속 값이나 열에는 효과가 있습니다 .

아렐 테이블

당신이 공상을 원한다면 당신은 사용할 수 있습니다 Arel::Table.

User.where(User.arel_table[:id].gt(200))

SQL을 생성합니다

"SELECT `users`.* FROM `users` WHERE (`users`.`id` > 200)"

구체적인 내용은 다음과 같습니다.

User.arel_table              #=> an Arel::Table instance for the User model / users table
User.arel_table[:id]         #=> an Arel::Attributes::Attribute for the id column
User.arel_table[:id].gt(200) #=> an Arel::Nodes::GreaterThan which can be passed to `where`

이 방법을 사용하면 관심 있는 정확한 SQL을 얻을 수 있지만 많은 사람들이 Arel 테이블을 직접 사용하지 않으며 혼란스럽고 혼란 스럽습니다. 당신과 당신의 팀은 당신에게 가장 적합한 것을 알게 될 것입니다.

보너스

Rails 5부터 날짜와 함께 할 수도 있습니다!

User.where(created_at: 3.days.ago..DateTime::Infinity.new)

SQL을 생성합니다

SELECT `users`.* FROM `users` WHERE (`users`.`created_at` >= '2018-07-07 17:00:51')

더블 보너스

Ruby 2.6이 출시되면 (2018 년 12 월 25 일) 새로운 무한 범위 구문을 사용할 수 있습니다! 대신 201..Float::INFINITY당신은 그냥 쓸 수 201..있습니다. 이 블로그 게시물에 더 많은 정보 있습니다.


3
이것이 호기심으로 받아 들여진 대답보다 우수한 이유는 무엇입니까?
mecampbellsoup

5
우월은 오도합니다. 일반적으로 문자열보다 해시 구문을 사용할 수 있다면 ARel 쿼리를 통해 더 많은 유연성을 얻을 수 있으므로 많은 사람들이이 솔루션을 선호합니다. 프로젝트 / 팀 / 조직에 따라 코드를 보는 사람이 이해하기 쉬운 것을 원할 수도 있습니다.
Aaron

2
기본 where매처 를 사용하여 그렇게 할 수 있다고 생각하지 않습니다 . 들어 >나는를 사용하는 것이 좋습니다 >= (number_you_want + 1)단순화를 위해. 정말로 >쿼리 인지 확인 하려면 ARel 테이블에 액세스 할 수 있습니다. 상속받은 모든 클래스 ActiveRecord에는 해당 클래스 arel_tableArel::Table를 반환 하는 getter 메소드가 있습니다. 테이블의 열은 []같은 방법 으로 액세스됩니다 User.arel_table[:id]. 이 반환은 Arel::Attributes::Attribute당신이 호출 할 수 있습니다 gt에와에 전달합니다 200. 그런 다음에 전달 될 수 있습니다 where. 예 User.where(User.arel_table[:id].gt(200)).
Aaron

2
@bluehallu 예제를 제공해 줄 수 있습니까? 다음은 나를 위해 작동하지 않습니다 User.where(created_at: 3.days.ago..DateTime::Infinity.new).
Aaron

1
아! Rails 5의 새로운 변화 일 것입니다. Rails 4.2.5 (Ruby 2.2.2)에서 WHERE (users.created_at >= '2016-04-09 14:31:15' AND users.created_at < #<Date::Infinity:0x00>)(SO 주석 형식화를 위해 생략 된 테이블 및 열 이름 주위의 역진)이있는 쿼리가 표시됩니다.
Aaron

22

더 나은 사용법은 사용자 모델에서 범위를 만드는 것입니다 where(arel_table[:id].gt(id))


6

보다 직관적 인 글을 원한다면, 다음 과 같이 당신의 지시를 쓸 수있게 해주는 squeel 이라는 보석 이 있습니다 :

User.where{id > 200}

'중괄호'문자 {}이며 id텍스트 일뿐입니다.

Gemfile에 squeel을 추가하기 만하면됩니다.

gem "squeel"

이렇게하면 Ruby에서 복잡한 SQL 문을 작성할 때 인생을 많이 편하게 할 수 있습니다.


11
압박을 사용하지 않는 것이 좋습니다. 장기적으로 유지 관리가 어렵고 때로는 이상한 행동을합니다. 또한 특정 Active Record 버전에서는 버그가 있습니다
John Owen Chile

나는 몇 년 동안 squeel을 사용해 왔으며 여전히 행복합니다. 그러나 sequel (<> squeel)과 같은 다른 ORM을 사용해 볼 가치가 있습니다 .ActiveRecord를 대체 할 수있는 유망한 기능입니다.
더글러스

5

아렐은 당신의 친구입니다.

User.where (사용자 .arel_table [: id] .gt (200))


4

또 다른 멋진 가능성은 ...

User.where("id > :id", id: 100)

이 기능을 사용하면 예를 들어 여러 장소에서 교체하려는 경우 더 이해하기 쉬운 쿼리를 만들 수 있습니다.

User.where("id > :id OR number > :number AND employee_id = :employee", id: 100, number: 102, employee: 1205)

이것은 ?쿼리에 많은 것을 갖는 것보다 더 의미가 있습니다 ...

User.where("id > ? OR number > ? AND employee_id = ?", 100, 102, 1205)

3

나는 종종 날짜 필드 (비교 연산자가 매우 일반적인 경우) 에이 문제가 있습니다.

나는 Mihai의 대답에 대해 더 자세히 설명합니다.

모델에 다음과 같이 범위를 추가 할 수 있습니다.

scope :updated_at_less_than, -> (date_param) { 
  where(arel_table[:updated_at].lt(date_param)) }

... 그리고 컨트롤러 또는 모델을 사용하는 모든 곳에서 :

result = MyModel.updated_at_less_than('01/01/2017')

... 조인이있는보다 복잡한 예는 다음과 같습니다.

result = MyParentModel.joins(:my_model).
  merge(MyModel.updated_at_less_than('01/01/2017'))

이 방법의 큰 장점은 (a) 서로 다른 범위에서 쿼리를 작성할 수있게하고 (b) arel_table이 쿼리 생성의 해당 부분을 처리하므로 동일한 테이블에 두 번 조인 할 때 별칭 충돌을 방지한다는 것입니다.


1

레일스 6.1+

Rails 6.1은 다음과 같은 where조건 에서 비교 연산자를위한 새로운 '구문'을 추가했습니다 .

Post.where('id >': 9)
Post.where('id >=': 9)
Post.where('id <': 3)
Post.where('id <=': 3)

따라서 다음과 같이 쿼리를 다시 작성할 수 있습니다.

User.where('id >': 200) 

다음은 더 많은 예제를 찾을 수있는 PR 링크 입니다.


-3

더 짧은 :

User.where("id > 200")

8
나는 이것이 동적이어야하고 포스터는 매개 변수화 된 쿼리 ( where("id > ?", 200)구문)를 사용하여 SQL 삽입을 피하려고한다고 가정합니다 . 이것은 그것을 달성하지 못합니다.
Matthew Hinea
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.