In postgres, NULL is treat as a speical value, that which is not equal to any other value, which means the expression
NULL = NULL yields false.
It can be verified by using the following query
The query returns empty set, because no element equals to NULL even NULL itself.
If you think this experiment is not convincing enough, then you can try this:
This query should yield “ , NOT NULL” which means NULL does not equal to NULL.
To test whether or whether not a value equals to NULL, you should use IS NULL or IS NOT NULL
So if you replace the
n = NULL with
n IS NULL in previous 2 statements, you will get expected result:
In most cases, the NULL special character doesn’t hurt much, since we always can alter our expression to fix the problem. But if you’re using table functions to create pivot, and there is NULL in your columns, then you will find
NULL is a cursed value, which brought a lot of trouble to you.
tablefunc extension, which can provide a series functions called “crosstab#”. And with these functions, you can convert a set of rows into a pivot table.
crosstab accept 2 sql queries. First query should yield 3 columns: row in pivot table, column in pivot table and value in pivot table.
Second query should yield a series of value which defines the columns of the pivot table.
crosstab function will group the rows yield by 1st query by 1st column. Then map each row in the group to a column by comparing the 2nd column in the row yield by 1st query with the value generated by 2nd query, if the value is equal then the 3rd column of the row yield by 1st query will be placed in the column defined by value of the 2nd query.
It if a very convenient feature provided by postgres, and it works perfect in most cases.
But in our case, we met a problem that we have
NULL value in the 2nd column of 1st query, which means we have
NULL value in pivot table columns!
And the crosstab decide which column the value should be placed to by comparing the whether the value is equal!
NULL never equals to
As a result, the column of
NULL in the pivot table is always empty!
To solve the problem, we should play a little trick in the first query, we should translate all the
NULL into a “normal” value.
Here is our 1st query, and we want to get a pivot table with period as row axis, rating as column axis and volume of the order as content.
And we will get
Profiles.rating, so we can translate
NULL as 0 in rating. To achieve this we can use
CASE WHEN statement.
The solution works fine. But in personal perspective, I don’t like it, because it repeat the statement and is not concise. But luckily, the value we should deal with the the special value
NULL and postgres has provided a group of functions to deal with
What we want is the function
COALESCE, which accept a group of value as arguments, and returns the first not null value.
So we can simplify our statement with this super function:
In the statement, if the rating is not null, the
COALESCE function will return the actual value if the rating is
NULL, then the
COALESCE will find the next not null value, which must be 0.
COALESCE function, there is another function called
NULLIF, which might mislead you to a totally wrong way just as what I had.
According to postgres document, the function might behave in a totally opposite way than you expected.
The NULLIF function returns a null value if value1 equals value2; otherwise it returns value1. This can be used to perform the inverse operation of the COALESCE