#13312 closed New feature (fixed)
Add a way to customize the order_by() of null fields
Reported by: | Sergey Dobrov | Owned by: | Mariusz Felisiak |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Normal | Keywords: | ordering, order_by, null |
Cc: | contact@…, serhiy.int@…, markus.magnuson@…, josh.smeaton@…, github@… | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Applying order_by on null=True fields gives different results on mysql and pgsql: pgsql thinks that NULL values are bigger than any and mysql that smaller. I think that this must be unified on all engines for prevent problems with portability. pgsql has additional parameter for this:
SELECT select_list FROM table_expression ORDER BY sort_expression1 [ASC | DESC] [NULLS { FIRST | LAST }] [, sort_expression2 [ASC | DESC] [NULLS { FIRST | LAST }] ...]
But I don't know how it on other engines.
Change History (27)
comment:1 by , 15 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
comment:2 by , 15 years ago
that's ok, but there is no way to control this behavior. i mean that i can't tell pgsql that i want nulls to be less than others in any good way. :(
comment:3 by , 14 years ago
Keywords: | null added |
---|
Just to document it, there is a very easy way to control this behavior. The most portable seems to be an additional order by for "field IS NULL". It puts NULLs last in at least sqlite3, mysql and PostgreSQL. The reverse is either "field IS NULL DESC" or "field IS NOT NULL".
It's also easy to use in a Django way:
q = q.extra(select={'null1':'field1 is null','null2':'field2 is null'}) q = q.extra(order_by=['null1','-field1','-null2','field2'])
Because it's so easy to do in a standard way, it might be worth at some point to add a specific queryset for it (not necessarily modifying order_by()), as extra() is not always desirable. Having a new queryset would allow backend specific optimization, like nulls last/first if supported.
comment:5 by , 9 years ago
Easy pickings: | unset |
---|---|
Severity: | → Normal |
Type: | → Uncategorized |
UI/UX: | unset |
See http://stackoverflow.com/a/35494930/15690, which uses a specilaized QuerySet/Query.
The extra()
approach is deprecated, and won't work with foreign keys / joined tables.
comment:6 by , 9 years ago
Resolution: | wontfix |
---|---|
Status: | closed → new |
Now that we have expressions, I think it's fine to reopen this ticket. We can introduce a OrderNulls.last()/.first()
expression to handle this in a standard way. We could also just build it right into the OrderBy
expression:
qs.order_by(F('my_field').asc().nullslast())
If we do build this into the existing order_by, you'll need to be careful about preserving a 'feature' that stops django from inserting duplicate ordering clauses (it builds each component then does a string compare to ensure the new clause isn't a duplicate).
This won't normalise order by nulls across backends, but it'll allow users to control null handling semantics if they have a use for it. NULL handling was originally going to be added to the OrderBy expression, but I ran out of time before that could happen.
comment:7 by , 9 years ago
Summary: | order_by on null-field gives different results on different db engines → Add a way to customize the order_by() of null fields |
---|---|
Triage Stage: | Unreviewed → Accepted |
Type: | Uncategorized → New feature |
Version: | 1.1 → master |
comment:8 by , 9 years ago
Cc: | added |
---|
comment:9 by , 9 years ago
Cc: | added |
---|
comment:10 by , 9 years ago
AFAIU, it's possible in all main supported engines:
ORDER BY IF(ISNULL(my_field),1,0),my_field in MySQL
[NULLS { FIRST | LAST }] in both PostgreSQL and Oracle
ORDER BY col1 IS NULL in SqLite3
comment:11 by , 8 years ago
Cc: | added |
---|
comment:12 by , 8 years ago
Cc: | added |
---|
comment:13 by , 8 years ago
Cc: | added |
---|
comment:15 by , 8 years ago
Patch needs improvement: | set |
---|
Comments for improvement are on the PR. Please uncheck "Patch needs improvement" after you update it an add documentation (see our PatchReviewChecklist).
comment:16 by , 8 years ago
Patch needs improvement: | unset |
---|
comment:17 by , 8 years ago
Needs documentation: | set |
---|
comment:18 by , 8 years ago
Needs documentation: | unset |
---|---|
Patch needs improvement: | set |
comment:20 by , 8 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:21 by , 8 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
Looking good pending some cosmetic changes.
comment:23 by , 8 years ago
What about one parameter with three possible values?
nulls_first:
- True: nulls at first
- False: nulls at last
- None (default): database default ordering
comment:24 by , 8 years ago
I don't like the idea of three-value logic here, because it imposes a slight burden when reading. It just seems unnecessary when there's nothing wrong with two kwarg options.
comment:25 by , 8 years ago
@Cloudream see the discussion on the original PR about why nulls_first
and nulls_last
were chosen.
I think this is one of those cases where we really just have to tell people to know the behavior of the DB they choose to use;
NULL
-handling in all its many forms is one of those things that's just not worth the time and complexity of abstraction.