带字符串文字的Postgresql COALESCE无法按预期工作

时间:2018-09-30 20:45:20

标签: sql postgresql coalesce

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

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's COALESCE is non-standard,让我怀疑是否真的是我。

引用:

  

行类型为COALESCE

     

该规范将COALESCE(X,Y)定义为对CASE的句法转换,当X不为空则X否则为Y END(它通过禁止非确定性表达式或带有在这种情况下的副作用)。这样的结果是,对行类型的空测试应用了相当奇怪的规则。   PostgreSQL仅对X应用“不是空值”测试。因此,如果X是包含空列的行值,则PostgreSQL将返回X,而规范将要求返回Y。

(可爱的解释,对吧?)

我还遇到了一些信息,这些信息指示COALESCE数据类型必须匹配,否则该功能会自动失败。 (!)

我希望将字符串文字'Total'解释为varchar,而column_1在数据库中定义为varchar(12),但目前我不确定有什么要帮助的,非常感谢。

2 个答案:

答案 0 :(得分:2)

问题是这样的:

group by rollup(coalesced_value)

您将根据应用coalesce()之后的值 进行分组。因此,rollup随后将生成null值。

相反,按数据中的列分组:

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值。它们是第一个,因为排序是递增的(默认情况下)。

答案 1 :(得分:1)

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

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中使用:

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;