내 Rails 앱에서 다른 사람들이 어떻게 해결하는지 알고 싶은 문제가 몇 번 발생했습니다.
값이 선택 사항 인 특정 레코드가 있으므로 일부 레코드에는 값이 있고 일부 레코드는 해당 열에 대해 null입니다.
일부 데이터베이스에서 해당 열을 기준으로 정렬하면 null이 먼저 정렬되고 일부 데이터베이스에서는 null이 마지막으로 정렬됩니다.
예를 들어, 컬렉션에 속할 수도 있고 아닐 수도있는 사진이 있습니다. 즉, 사진이 어디에 collection_id=nil
있고 일부가 있습니다 collection_id=1
.
그런 Photo.order('collection_id desc)
다음 SQLite에서 마지막으로 null을 얻지 만 PostgreSQL에서는 먼저 null을 얻습니다.
이를 처리하고 모든 데이터베이스에서 일관된 성능을 얻을 수있는 멋진 표준 Rails 방법이 있습니까?
답변
배열을 함께 추가하면 순서가 유지됩니다.
@nonull = Photo.where("collection_id is not null").order("collection_id desc")
@yesnull = Photo.where("collection_id is null")
@wanted = @nonull+@yesnull
답변
저는 SQL 전문가는 아니지만 무언가가 null 인 경우 먼저 정렬 한 다음 원하는 정렬 방식으로 정렬하지 않는 이유는 무엇입니까?
Photo.order('collection_id IS NULL, collection_id DESC') # Null's last
Photo.order('collection_id IS NOT NULL, collection_id DESC') # Null's first
PostgreSQL 만 사용하는 경우 다음을 수행 할 수도 있습니다.
Photo.order('collection_id DESC NULLS LAST') #Null's Last
Photo.order('collection_id DESC NULLS FIRST') #Null's First
보편적 인 것을 원한다면 (여러 데이터베이스에서 동일한 쿼리를 사용하는 것과 같이 (@philT 제공))
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
답변
지금은 2017 년이지만, NULL
s가 우선해야하는지 에 대한 합의는 아직 없습니다 . 그것에 대해 명시하지 않으면 결과는 DBMS에 따라 달라질 것입니다.
표준은 NULL이 아닌 값과 비교하여 NULL을 정렬하는 방법을 지정하지 않습니다. 단 두 개의 NULL이 동일한 순서로 간주되고 NULL이 모든 NULL이 아닌 값의 위 또는 아래로 정렬되어야한다는 점을 제외하고는 예외입니다.
문제를 설명하기 위해 Rails 개발과 관련하여 가장 많이 사용되는 몇 가지 사례 목록을 작성했습니다.
PostgreSQL
NULL
의 값이 가장 높습니다.
기본적으로 null 값은 null이 아닌 값보다 큰 것처럼 정렬됩니다.
MySQL
NULL
의 값이 가장 낮습니다.
ORDER BY를 수행 할 때 ORDER BY … ASC를 수행하면 NULL 값이 먼저 표시되고 ORDER BY … DESC를 수행하면 마지막으로 표시됩니다.
SQLite
NULL
의 값이 가장 낮습니다.
NULL 값이있는 행은 오름차순으로 일반 값이있는 행보다 높으며 내림차순으로 반전됩니다.
해결책
불행히도 Rails 자체는 아직 이에 대한 솔루션을 제공하지 않습니다.
PostgreSQL 관련
PostgreSQL의 경우 매우 직관적으로 사용할 수 있습니다.
Photo.order('collection_id DESC NULLS LAST') # NULLs come last
MySQL 특정
MySQL의 경우 마이너스 기호를 미리 입력 할 수 있지만이 기능은 문서화되지 않은 것 같습니다. 숫자 값뿐만 아니라 날짜에서도 작동하는 것처럼 보입니다.
Photo.order('-collection_id DESC') # NULLs come last
PostgreSQL 및 MySQL 관련
두 가지를 모두 다루려면 다음과 같이 작동합니다.
Photo.order('collection_id IS NULL, collection_id DESC') # NULLs come last
그러나 이것은 SQLite에서 작동하지 않습니다 .
범용 솔루션
모든 DBMS에 대한 교차 지원을 제공하려면 CASE
이미 @PhilIT에서 제안한를 사용하여 쿼리를 작성해야합니다 .
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
이는 각 레코드를 먼저 CASE
결과 (기본적으로 오름차순, 즉 NULL
값이 마지막 값이 됨을 의미 함) 별로 먼저 정렬 하고 두 번째는 calculation_id
.
답변
Photo.order('collection_id DESC NULLS LAST')
나는 이것이 오래된 것임을 알고 있지만 방금이 스 니펫을 찾았고 그것은 나를 위해 작동합니다.
답변
넣고 빼기 기호를 COLUMN_NAME 앞에와 순서의 방향을 반대로. mysql에서 작동합니다. 자세한 내용은
Product.order('something_date ASC') # NULLS came first
Product.order('-something_date DESC') # NULLS came last
답변
쇼에 조금 늦었지만 일반적인 SQL 방식이 있습니다. 평소와 같이 CASE
구조합니다.
Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
답변
가장 쉬운 방법은 다음을 사용하는 것입니다.
.order('name nulls first')