Rails: Order with nulls last

后端 未结 10 1468
悲哀的现实
悲哀的现实 2020-11-30 19:12

In my Rails app I\'ve run into an issue a couple times that I\'d like to know how other people solve:

I have certain records where a value is optional, so some recor

相关标签:
10条回答
  • 2020-11-30 19:42

    I'm no expert at SQL, but why not just sort by if something is null first then sort by how you wanted to sort it.

    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
    

    If you are only using PostgreSQL, you can also do this

    Photo.order('collection_id DESC NULLS LAST')  #Null's Last
    Photo.order('collection_id DESC NULLS FIRST') #Null's First
    

    If you want something universal (like you're using the same query across several databases, you can use (courtesy of @philT)

    Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
    
    0 讨论(0)
  • 2020-11-30 19:44

    Put minus sign in front of column_name and reverse the order direction. It works on mysql. More details

    Product.order('something_date ASC') # NULLS came first
    Product.order('-something_date DESC') # NULLS came last
    
    0 讨论(0)
  • 2020-11-30 19:44

    In my case I needed sort lines by start and end date by ASC, but in few cases end_date was null and that lines should be in above, I used

    @invoice.invoice_lines.order('start_date ASC, end_date ASC NULLS FIRST')

    0 讨论(0)
  • 2020-11-30 19:51

    Even though it's 2017 now, there is still yet to be a consensus on whether NULLs should take precedence. Without you being explicit about it, your results are going to vary depending on the DBMS.

    The standard doesn't specify how NULLs should be ordered in comparison with non-NULL values, except that any two NULLs are to be considered equally ordered, and that NULLs should sort either above or below all non-NULL values.

    source, comparison of most DBMSs

    To illustrate the problem, I compiled a list of a few most popular cases when it comes to Rails development:

    PostgreSQL

    NULLs have the highest value.

    By default, null values sort as if larger than any non-null value.

    source: PostgreSQL documentation

    MySQL

    NULLs have the lowest value.

    When doing an ORDER BY, NULL values are presented first if you do ORDER BY ... ASC and last if you do ORDER BY ... DESC.

    source: MySQL documentation

    SQLite

    NULLs have the lowest value.

    A row with a NULL value is higher than rows with regular values in ascending order, and it is reversed for descending order.

    source

    Solution

    Unfortunately, Rails itself doesn't provide a solution for it yet.

    PostgreSQL specific

    For PostgreSQL you could quite intuitively use:

    Photo.order('collection_id DESC NULLS LAST') # NULLs come last

    MySQL specific

    For MySQL, you could put the minus sign upfront, yet this feature seems to be undocumented. Appears to work not only with numerical values, but with dates as well.

    Photo.order('-collection_id DESC') # NULLs come last

    PostgreSQL and MySQL specific

    To cover both of them, this appears to work:

    Photo.order('collection_id IS NULL, collection_id DESC') # NULLs come last

    Still, this one does not work in SQLite.

    Universal solution

    To provide cross-support for all DBMSs you'd have to write a query using CASE, already suggested by @PhilIT:

    Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')

    which translates to first sorting each of the records first by CASE results (by default ascending order, which means NULL values will be the last ones), second by calculation_id.

    0 讨论(0)
  • 2020-11-30 19:51

    The easiest way is to use:

    .order('name nulls first')

    0 讨论(0)
  • 2020-11-30 19:52

    Bit late to the show but there is a generic SQL way to do it. As usual, CASE to the rescue.

    Photo.order('CASE WHEN collection_id IS NULL THEN 1 ELSE 0 END, collection_id')
    
    0 讨论(0)
提交回复
热议问题