Sort NULL values to the end of a table
NULL
values are sorted last in default ascending order. You don't have to do anything extra.
The issue applies to descending order, which is the perfect inverse and thus sorts NULL
values on top.
PostgreSQL 8.3 introduced NULLS LAST
:
ORDER BY somevalue DESC NULLS LAST
For PostgreSQL 8.2 and older or other RDBMS without this standard SQL feature:
ORDER BY (somevalue IS NULL), somevalue DESC
FALSE
sorts before TRUE
, so NULL
values come last, just like in the example above.
See:
- Sort by column ASC, but NULL values first?
- The manual on
SELECT
How to sort a column in ascending order with NULL values at the end?
If you calculate anything on the date field, you'll loose the use of the index on that.
So check for Null:
SELECT
startdate, id
FROM
YourTable
ORDER BY
StartDate Is Null,
StartDate
How to handle null values inside my sort by function?
The challenge is about sorting numbers OR text with the same function, based on a column name and a direction. The difficulty is about making sure we deal with a number or with text... to apply the right .sort()
callback.
Additionally, there are two things to take in account:
- Some strings may need to be "reformatted" as numbers
- Some values may be
null
and should always must ends up at the end of the sorting.
Okay! First, let's go through your functions from the first one:
sortedRowInformation(data, getComparator(orderDirection, valueToOrderBy)).map(...)
That sortedRowInformation
really looks like a .sort()
function nested in a .sort()
function... With two .map()
applied on a stabilizedRowArray
sub-array...
I have to admit I discarded it right away. I assumed the expected result by its pretty descriptive name and the 1st argument being the data
.
The second argument... Where getComparator()
is a function call with the two componant state properties as argument. That returns two possible functions (lol, the same function with or without a minus sign in front of its evaluation...). So calling that descendingComparator
function again calls another function numeric()
where our null
problem is.
And all this process to just return -1
, 0
or 1
to be used as that second argument for sortedRowInformation()
... Which is the basic .sort()
internal job.
Just describing this process should raise a big flag. You nicely overcomplicated everything.
Solution
Here are my solution explanations starting from the other end:The numeric()
function is okay to isolate as a function. But that is where you had difficulties due to the null
values coming in 3 functions above... So what if we put the null
values aside from that logic and always assume a non-null value?
So now that we decided there is no null
values, we can test them more easily for number or string. Anyway there is a special case where a string can finally be a number when removing the $
and comas (thousand separator).
I came up with this custom isNumeric()
function:
function isNumeric(x) {
let value = !isNaN(x) ? x: parseFloat(x.replace(/[\$,]/g, ""))
return {isNum:!isNaN(value), value}
}
That function returns an object containing a boolean and a "processed" value: a number or NaN
.
Now... Getting back to the starting point for the sorting, here is a function to sort the data
:
function sortAll(data, orderDirection, valueToOrderBy) {
// Filter the nulls in an array and the rest in another
let nulls = data.filter((item) => item[valueToOrderBy] == null)
let toSort = data.filter((item) => item[valueToOrderBy])
// Sort the non-null values
let sorted = toSort.sort((a, b) => {
// Check if both values are numeric
let aa = isNumeric(a[valueToOrderBy])
let bb = isNumeric(b[valueToOrderBy])
// If numerics
if (aa.isNum && bb.isNum) {
return aa.value - bb.value
}
// If strings
return (a[valueToOrderBy]).toLowerCase() > (b[valueToOrderBy]).toLowerCase() ? 1 : -1;
});
// The sorting direction
if (orderDirection === "desc") {
sorted.reverse();
}
// Add the nulls at the end of the returned array
return sorted.concat(nulls);
}
So to apply it in your React component return is:
sortAll(data, orderDirection, valueToOrderBy).map(...)
instead of:
sortedRowInformation(data, getComparator(orderDirection, valueToOrderBy)).map(...)
Squarely discard those functions: sortedRowInformation
, getComparator
and descendingComparator
and replace numeric
with my isNumeric
.
Here is a CodePen where I tested the sorting cases with some feak data
.
If it does not already work in all cases with your data
... At least, it is way easier to improve. ;)
How to sort NULL values last - for grouping summary rows with group by rollup/cube
Just change
ORDER BY Year, Quarter
to
ORDER BY GROUPING(Year), Year, GROUPING(Quarter), Quarter
Explanation: this function returns 1 for total rows and 0 for all others.
custom sorting v-data-table with null values last
Your sorting algorithm is not working correctly for strings.
Imagine that your first string is null
, and the second one is 'Jelly bean'
.
Instead of null
value you are trying to compate Infinity
with 'Jelly bean'
.
This comparison will be false
in both cases:
let a = Infinity;
let b = 'Jelly bean';
console.log(a > b);
console.log(a < b);
SQL how to make null values come last when sorting ascending
select MyDate
from MyTable
order by case when MyDate is null then 1 else 0 end, MyDate
mat-sort ascending with null values to last
My solution was, making a custom sort and hooking to ngAfterViewInit:
ngAfterViewInit() {
this.dataSource.sortData = (data, sort: MatSort) => {
let sortedData = [];
sortedData = data.sort((a, b) => {
const direction = this.getSortingOrder(sort.direction, a, b);
if (!direction[0][sort.active] || !direction[1][sort.active]) {
return sort.direction === "asc" ? 0 : -1;
} else {
return direction[0][sort.active]
.toString()
.localeCompare(direction[1][sort.active]);
}
});
return sortedData;
};
}
getSortingOrder = (order, a, b) => {
const sorted = order === "asc" ? [a, b] : [b, a];
return sorted;
}
This will push the null values to last when sorted by ascending
Related Topics
How to Anticipate and Escape Single Quote ' in Oracle
How to Select Date Without Time in SQL
SQL Server: Get Total Days Between Two Dates
Grouped String Aggregation/Listagg for SQL Server
Procedure or Function !!! Has Too Many Arguments Specified
How to Get the Size of a Varchar[N] Field in One SQL Statement
Can an Inner Join Offer Better Performance Than Exists
Bulk Insert Using Stored Procedure
Count Returning Blank Instead of 0
A Way to Extract from a Datetime Value Data Without Seconds
SQL - Query to Get Server's Ip Address
String Concatenation Does Not Work in SQLite
Custom Function with Check Constraint SQL Server 2008
Why Doesn't SQL Support "= Null" Instead of "Is Null"