2

I'm on Rails 4 and have a begin_date:date attribute on a Project model. I'm using ActiveRecord, and the following request returns different results on Postgres vs SQLite when there are nil values:

User.first.projects.order(begin_date: :desc, end_date: :desc)

In Postgres nil values are treated as of higher value than existing value (hence come first), while in SQLite records with nil value comes last.

  1. Am I doing something wrong or is this the expected behaviour?

  2. How could I reconstruct the above query such that it renders equal results (in regard of nil values) on both Postgres and SQLite?

PS. Please, if you have strong opinions that I should use the same db technology in all environments: I thank you for your consideration, but I know about this and this question is not about that subject.

2
  • Which end do you want your nulls on? Commented Dec 27, 2013 at 1:51
  • I would prefer to rank them lower than records with existing values. Commented Dec 27, 2013 at 1:53

1 Answer 1

3

Since the default behavior is different across databases, you need to specify the treatment of NULL explicitly.

There are a several ways to do this, but the most portable seems to be described in ORDER BY DATE showing NULLS first then most recent dates and SQL how to make null values come last when sorting ascending, which use a CASE statement to explicitly handle the treatment of null values.

In your case, it would like something like:

order('case when begin_date is null then 1 else 0 end,
     begin_date desc, case when end_date is null then 1 else 0 end, end_date desc')

depending on where you want to nulls to sort. You'd swap the 1s and the 0s if you wanted the nulls to be sorted first.

Another approach would be to sort by an expression with converts nulls into something non-null. I'm not sure what the SQL standard is in this regard in terms of ISNULL, NVL, IFNULL and COALESCE or even which of this is common to both sqllite and postgres.

This recent thread discusses the lack of (and need for) a mechanism within Rails to support this through order.

Sign up to request clarification or add additional context in comments.

8 Comments

Hm, interesting. And a bit sad. Do you possibly have any explicit code suggestion for my case, when it comes to order by two columns as well (i.e. if first equal, order by second)?
You can also use COALESCE(begin_date, X) to convert the NULLs to something more predictable (assuming the existence of suitable Xs of course).
Yes and AFAIK everyone else is starting to track the standard on this one little tiny thing. Finally. So you can COALESCE in both SQLite and PostgreSQL (and even MySQL).
@muistooshort Would you care to elaborate how an implementation with COALESCE in the above scenario could look like?
It would look like Gratzy's answer to one of the linked questions. The problem with COALESCE is also noted over there.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.