关于sql:带有字符串文字的Postgresql COALESCE无法按预期工作

Postgresql COALESCE with String Literals does not work as expected

我正在尝试从汇总中输出和标记总计列。

1
2
3
4
5
6
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

该查询工作正常,并按预期生成了总计,但是我希望是"总计"的列值显示为[null]。

我很有可能是我缺乏某种理解,但是这说明PostgreSQL的COALESCE是非标准的,这让我怀疑它是否真的是我。

报价:

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.

(可爱的解释,对吧?)

我还遇到了一些信息,这些信息指示COALESCE数据类型必须匹配,否则该功能将以静默方式失败。 (!)

我希望将字符串文字'Total'解释为varchar,而column_1在数据库中定义为varchar(12),但是目前我还不确定有什么事情,任何帮助将不胜感激 。


问题是这样的:

1
GROUP BY rollup(coalesced_value)

应用coalesce()之后,将按值分组。 因此,rollup然后生成null值。

而是,按数据中的列分组:

1
2
3
4
5
6
7
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;

这将按照您想要的方式显式排序结果。 没有它,结果将是您想要的(我认为)。 第一部分(column1 is null)::int是转换为数字的布尔表达式。 Null值是true,并分配值为1;否则为0。 非NULL值被赋值为0。这些是第一个,因为排序是递增的(默认情况下)。


我不是POSTGRESQL的专家,但是我仍然可以提供一些见解。 最简单的方法是只使用子查询:

1
2
3
4
5
6
7
8
9
10
11
SELECT COALESCE(column_1,'Total') AS coalesced_value
,column_sum
FROM
(
SELECT column_1
,SUM(column_2) AS column_sum
FROM TABLE
WHERE yada yada
GROUP BY rollup(column_1)
) a
ORDER BY coalesced_value;

如果要避免子查询,则应该可以使用GROUPING函数。 我知道这在Teradata SQL中有效,但是经过一番谷歌搜索之后,它似乎也应该在POSTGRESQL中工作:

1
2
3
4
5
6
7
SELECT CASE WHEN GROUPING(column_1) = 1 THEN 'Total'
ELSE column_1 END AS grouping_value
,SUM(column_2) AS column_sum
FROM TABLE
WHERE yada yada
GROUP BY rollup(column_1)
ORDER BY grouping_value;