I'm trying to output and label a column total from a rollup.
select coalesce(column_1, 'Total') as coalesced_value,
sum(column_2) as column_sum
from table
where yada yada
group by rollup(coalesced_value)
order by coalesced_value
The query works fine and generates a total as expected, but the column value that I would expect to be 'Total' shows up as [null].
There's a good chance it's probably some lack of understanding on my part, but then there's this that says that PostgreSQL's COALESCE is non-standard and makes me wonder if it's really me.
To quote:
COALESCE on row types
The spec defines COALESCE(X,Y) as a syntactic transformation to CASE WHEN X IS NOT NULL THEN X ELSE Y END (it leaves open the question of whether X is really evaluated twice by disallowing non-deterministic expressions or expressions with side effects in this context). A consequence of this is that the rather odd rules for null tests of row types are applied. PostgreSQL applies only the "is not the null value" test to X. Accordingly, if X is a row value containing null columns, PostgreSQL will return X, while the spec would require returning Y.
(Lovely explanation, right?)
I also ran across some information that indicates that COALESCE data types have to match, otherwise the function fails silently. (!)
I would expect the string literal 'Total' to be interpreted as a varchar, and column_1 is defined in the database as a varchar(12), but at this point I am not sure of much of anything, and any help would be most appreciated.
The problem is this:
group by rollup(coalesced_value)
You are grouping by the value after the coalesce()
is applied. Hence, the rollup
is then generating the null
value.
Instead, group by the column that is in the data:
select coalesce(column_1, 'Total') as coalesced_value,
sum(column_2) as column_sum
from table
where yada yada
group by rollup(column_1)
order by (column_1 is null)::int, -- put the total at the end
coalesced_value;
This explicitly orders the results in the way that you want them. The results will be what you want without it (I think). The first part (column1 is null)::int
is a boolean expression converted to a number. Null values are true and assigned a value of 1; non-NULL values are assigned a value of 0. These are first, because the sort is ascending (by default).